This source code is licensed under the MIT license found in the LICENSE file in the root
- * directory of this source tree.
- */
-package com.expensify.chat;
-
-import android.content.Context;
-import com.facebook.flipper.android.AndroidFlipperClient;
-import com.facebook.flipper.android.utils.FlipperUtils;
-import com.facebook.flipper.core.FlipperClient;
-import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
-import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
-import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
-import com.facebook.flipper.plugins.inspector.DescriptorMapping;
-import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
-import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
-import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
-import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
-import com.facebook.react.ReactInstanceEventListener;
-import com.facebook.react.ReactInstanceManager;
-import com.facebook.react.bridge.ReactContext;
-import com.facebook.react.modules.network.NetworkingModule;
-import okhttp3.OkHttpClient;
-
-/**
- * Class responsible of loading Flipper inside your React Native application. This is the debug
- * flavor of it. Here you can add your own plugins and customize the Flipper setup.
- */
-public class ReactNativeFlipper {
- public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
- if (FlipperUtils.shouldEnableFlipper(context)) {
- final FlipperClient client = AndroidFlipperClient.getInstance(context);
-
- client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
- client.addPlugin(new DatabasesFlipperPlugin(context));
- client.addPlugin(new SharedPreferencesFlipperPlugin(context));
- client.addPlugin(CrashReporterPlugin.getInstance());
-
- NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
- NetworkingModule.setCustomClientBuilder(
- new NetworkingModule.CustomClientBuilder() {
- @Override
- public void apply(OkHttpClient.Builder builder) {
- builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
- }
- });
- client.addPlugin(networkFlipperPlugin);
- client.start();
-
- // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
- // Hence we run if after all native modules have been initialized
- ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
- if (reactContext == null) {
- reactInstanceManager.addReactInstanceEventListener(
- new ReactInstanceEventListener() {
- @Override
- public void onReactContextInitialized(ReactContext reactContext) {
- reactInstanceManager.removeReactInstanceEventListener(this);
- reactContext.runOnNativeModulesQueueThread(
- new Runnable() {
- @Override
- public void run() {
- client.addPlugin(new FrescoFlipperPlugin());
- }
- });
- }
- });
- } else {
- client.addPlugin(new FrescoFlipperPlugin());
- }
- }
- }
-}
diff --git a/android/app/src/main/java/com/expensify/chat/MainActivity.java b/android/app/src/main/java/com/expensify/chat/MainActivity.java
deleted file mode 100644
index e9f84039cf8a..000000000000
--- a/android/app/src/main/java/com/expensify/chat/MainActivity.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.expensify.chat;
-import expo.modules.ReactActivityDelegateWrapper;
-
-import android.os.Bundle;
-import android.content.pm.ActivityInfo;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.WindowInsets;
-
-import com.expensify.chat.bootsplash.BootSplash;
-import com.expensify.reactnativekeycommand.KeyCommandModule;
-import com.facebook.react.ReactActivity;
-import com.facebook.react.ReactActivityDelegate;
-import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
-import com.facebook.react.defaults.DefaultReactActivityDelegate;
-
-public class MainActivity extends ReactActivity {
-
- /**
- * Returns the name of the main component registered from JavaScript. This is used to schedule
- * rendering of the component.
- */
- @Override
- protected String getMainComponentName() {
- return "NewExpensify";
- }
-
- /**
- * Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link
- * DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React
- * (aka React 18) with two boolean flags.
- */
- @Override
- protected ReactActivityDelegate createReactActivityDelegate() {
- return new ReactActivityDelegateWrapper(this, BuildConfig.IS_NEW_ARCHITECTURE_ENABLED, new DefaultReactActivityDelegate(
- this,
- getMainComponentName(),
- // If you opted-in for the New Architecture, we enable the Fabric Renderer.
- DefaultNewArchitectureEntryPoint.getFabricEnabled()));
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- BootSplash.init(this);
- super.onCreate(null);
- if (getResources().getBoolean(R.bool.portrait_only)) {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- }
-
- // Sets translucent status bar. This code is based on what the react-native StatusBar
- // module does, but we need to do it here to avoid the splash screen jumping on app start.
- View decorView = getWindow().getDecorView();
- decorView.setOnApplyWindowInsetsListener(
- (v, insets) -> {
- WindowInsets defaultInsets = v.onApplyWindowInsets(insets);
- return defaultInsets.replaceSystemWindowInsets(
- defaultInsets.getSystemWindowInsetLeft(),
- 0,
- defaultInsets.getSystemWindowInsetRight(),
- defaultInsets.getSystemWindowInsetBottom());
- });
- }
-
- /**
- * This method is called when a key down event has occurred.
- * Forwards the event to the KeyCommandModule
- */
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- // Disabling hardware ESCAPE support which is handled by Android
- if (event.getKeyCode() == KeyEvent.KEYCODE_ESCAPE) {
- return false;
- }
- KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event);
- return super.onKeyDown(keyCode, event);
- }
-
- @Override
- public boolean onKeyLongPress(int keyCode, KeyEvent event) {
- // Disabling hardware ESCAPE support which is handled by Android
- if (event.getKeyCode() == KeyEvent.KEYCODE_ESCAPE) { return false; }
- KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event);
- return super.onKeyLongPress(keyCode, event);
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- // Disabling hardware ESCAPE support which is handled by Android
- if (event.getKeyCode() == KeyEvent.KEYCODE_ESCAPE) { return false; }
- KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event);
- return super.onKeyUp(keyCode, event);
- }
-}
diff --git a/android/app/src/main/java/com/expensify/chat/MainActivity.kt b/android/app/src/main/java/com/expensify/chat/MainActivity.kt
new file mode 100644
index 000000000000..935ba8c8825f
--- /dev/null
+++ b/android/app/src/main/java/com/expensify/chat/MainActivity.kt
@@ -0,0 +1,85 @@
+package com.expensify.chat
+
+import expo.modules.ReactActivityDelegateWrapper
+
+import android.content.pm.ActivityInfo
+import android.os.Bundle
+import android.view.KeyEvent
+import android.view.View
+import android.view.WindowInsets
+import com.expensify.chat.bootsplash.BootSplash
+import com.expensify.reactnativekeycommand.KeyCommandModule
+import com.facebook.react.ReactActivity
+import com.facebook.react.ReactActivityDelegate
+import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
+import com.facebook.react.defaults.DefaultReactActivityDelegate
+
+class MainActivity : ReactActivity() {
+ /**
+ * Returns the name of the main component registered from JavaScript. This is used to schedule
+ * rendering of the component.
+ */
+ override fun getMainComponentName() = "NewExpensify"
+
+ /**
+ * Returns the instance of the [ReactActivityDelegate]. Here we use a util class [ ] which allows you to easily enable Fabric and Concurrent React
+ * (aka React 18) with two boolean flags.
+ */
+ override fun createReactActivityDelegate() = ReactActivityDelegateWrapper(this, BuildConfig.IS_NEW_ARCHITECTURE_ENABLED, DefaultReactActivityDelegate(
+ this,
+ mainComponentName, // If you opted-in for the New Architecture, we enable the Fabric Renderer.
+ fabricEnabled
+ ))
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ BootSplash.init(this)
+ super.onCreate(null)
+ if (resources.getBoolean(R.bool.portrait_only)) {
+ requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
+ }
+
+ // Sets translucent status bar. This code is based on what the react-native StatusBar
+ // module does, but we need to do it here to avoid the splash screen jumping on app start.
+ val decorView = window.decorView
+ decorView.setOnApplyWindowInsetsListener { v: View, insets: WindowInsets? ->
+ val defaultInsets = v.onApplyWindowInsets(insets)
+ defaultInsets.replaceSystemWindowInsets(
+ defaultInsets.systemWindowInsetLeft,
+ 0,
+ defaultInsets.systemWindowInsetRight,
+ defaultInsets.systemWindowInsetBottom
+ )
+ }
+ }
+
+ /**
+ * This method is called when a key down event has occurred.
+ * Forwards the event to the KeyCommandModule
+ */
+ override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
+ // Disabling hardware ESCAPE support which is handled by Android
+ if (event.keyCode == KeyEvent.KEYCODE_ESCAPE) {
+ return false
+ }
+ KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event)
+ return super.onKeyDown(keyCode, event)
+ }
+
+ override fun onKeyLongPress(keyCode: Int, event: KeyEvent): Boolean {
+ // Disabling hardware ESCAPE support which is handled by Android
+ if (event.keyCode == KeyEvent.KEYCODE_ESCAPE) {
+ return false
+ }
+ KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event)
+ return super.onKeyLongPress(keyCode, event)
+ }
+
+ override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
+ // Disabling hardware ESCAPE support which is handled by Android
+ if (event.keyCode == KeyEvent.KEYCODE_ESCAPE) {
+ return false
+ }
+ KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event)
+ return super.onKeyUp(keyCode, event)
+ }
+}
diff --git a/android/app/src/main/java/com/expensify/chat/MainApplication.java b/android/app/src/main/java/com/expensify/chat/MainApplication.java
deleted file mode 100644
index 6e5db5d14ab3..000000000000
--- a/android/app/src/main/java/com/expensify/chat/MainApplication.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package com.expensify.chat;
-import android.content.res.Configuration;
-import expo.modules.ApplicationLifecycleDispatcher;
-import expo.modules.ReactNativeHostWrapper;
-
-import android.content.Context;
-import android.database.CursorWindow;
-
-import androidx.multidex.MultiDexApplication;
-
-import com.expensify.chat.bootsplash.BootSplashPackage;
-import com.facebook.react.PackageList;
-import com.facebook.react.ReactApplication;
-import com.facebook.react.ReactNativeHost;
-import com.facebook.react.ReactPackage;
-import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
-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 java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.util.List;
-
-public class MainApplication extends MultiDexApplication implements ReactApplication {
- private final ReactNativeHost mReactNativeHost =
- new ReactNativeHostWrapper(this, new DefaultReactNativeHost(this) {
- @Override
- public boolean getUseDeveloperSupport() {
- return BuildConfig.DEBUG;
- }
-
- @Override
- protected List getPackages() {
- @SuppressWarnings("UnnecessaryLocalVariable")
- List packages = new PackageList(this).getPackages();
- // Packages that cannot be autolinked yet can be added manually here, for example:
- // packages.add(new MyReactNativePackage());
- packages.add(new BootSplashPackage());
- packages.add(new ExpensifyAppPackage());
- packages.add(new RNTextInputResetPackage());
-
- return packages;
- }
-
- @Override
- protected String getJSMainModuleName() {
- return ".expo/.virtual-metro-entry";
- }
-
- @Override
- protected boolean isNewArchEnabled() {
- return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
- }
-
- @Override
- protected Boolean isHermesEnabled() {
- return BuildConfig.IS_HERMES_ENABLED;
- }
- });
-
- @Override
- public ReactNativeHost getReactNativeHost() {
- return mReactNativeHost;
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
-
- SoLoader.init(this, /* native exopackage */ false);
- if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
- // If you opted-in for the New Architecture, we load the native entry point for this app.
- DefaultNewArchitectureEntryPoint.load();
- }
- ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
-
- if (BuildConfig.DEBUG) {
- FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(false);
- }
-
- // Force the app to LTR mode.
- I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance();
- sharedI18nUtilInstance.allowRTL(getApplicationContext(), false);
-
- // Start the "js_load" custom performance tracing metric. This timer is stopped by a native
- // module in the JS so we can measure total time starting in the native layer and ending in
- // the JS layer.
- StartupTimer.start();
-
- // Increase SQLite DB write size
- try {
- Field field = CursorWindow.class.getDeclaredField("sCursorWindowSize");
- field.setAccessible(true);
- field.set(null, 100 * 1024 * 1024); //the 100MB is the new size
- } catch (Exception e) {
- e.printStackTrace();
- }
- ApplicationLifecycleDispatcher.onApplicationCreate(this);
- }
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig);
- }
-}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/expensify/chat/MainApplication.kt b/android/app/src/main/java/com/expensify/chat/MainApplication.kt
new file mode 100644
index 000000000000..193333368991
--- /dev/null
+++ b/android/app/src/main/java/com/expensify/chat/MainApplication.kt
@@ -0,0 +1,76 @@
+package com.expensify.chat
+
+import android.content.res.Configuration
+import android.database.CursorWindow
+import androidx.multidex.MultiDexApplication
+import com.expensify.chat.bootsplash.BootSplashPackage
+import com.facebook.react.PackageList
+import com.facebook.react.ReactApplication
+import com.facebook.react.ReactNativeHost
+import com.facebook.react.ReactPackage
+import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
+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 expo.modules.ApplicationLifecycleDispatcher
+import expo.modules.ReactNativeHostWrapper
+
+class MainApplication : MultiDexApplication(), ReactApplication {
+ override val reactNativeHost: ReactNativeHost = ReactNativeHostWrapper(this, object : DefaultReactNativeHost(this) {
+ override fun getUseDeveloperSupport() = BuildConfig.DEBUG
+
+ override fun getPackages(): List =
+ PackageList(this).packages.apply {
+ // Packages that cannot be autolinked yet can be added manually here, for example:
+ // add(MyReactNativePackage());
+ add(BootSplashPackage())
+ add(ExpensifyAppPackage())
+ add(RNTextInputResetPackage())
+ }
+
+ override fun getJSMainModuleName() = ".expo/.virtual-metro-entry"
+
+ override val isNewArchEnabled: Boolean
+ get() = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
+ override val isHermesEnabled: Boolean
+ get() = BuildConfig.IS_HERMES_ENABLED
+ })
+
+ override fun onCreate() {
+ super.onCreate()
+
+ SoLoader.init(this, /* native exopackage */false)
+ if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
+ // If you opted-in for the New Architecture, we load the native entry point for this app.
+ load()
+ }
+ if (BuildConfig.DEBUG) {
+ FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(false)
+ }
+
+ // Force the app to LTR mode.
+ val sharedI18nUtilInstance = I18nUtil.getInstance()
+ sharedI18nUtilInstance.allowRTL(applicationContext, false)
+
+ // Start the "js_load" custom performance tracing metric. This timer is stopped by a native
+ // module in the JS so we can measure total time starting in the native layer and ending in
+ // the JS layer.
+ StartupTimer.start()
+
+ // Increase SQLite DB write size
+ try {
+ val field = CursorWindow::class.java.getDeclaredField("sCursorWindowSize")
+ field.isAccessible = true
+ field[null] = 100 * 1024 * 1024 //the 100MB is the new size
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ ApplicationLifecycleDispatcher.onApplicationCreate(this);
+ }
+
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ super.onConfigurationChanged(newConfig)
+ ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig)
+ }
+}
diff --git a/android/app/src/release/java/com/expensify/chat/ReactNativeFlipper.java b/android/app/src/release/java/com/expensify/chat/ReactNativeFlipper.java
deleted file mode 100644
index 0e3c02f072e6..000000000000
--- a/android/app/src/release/java/com/expensify/chat/ReactNativeFlipper.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/**
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- *
This source code is licensed under the MIT license found in the LICENSE file in the root
- * directory of this source tree.
- */
-package com.expensify.chat;
-
-import android.content.Context;
-import com.facebook.react.ReactInstanceManager;
-
-/**
- * Class responsible of loading Flipper inside your React Native application. This is the release
- * flavor of it so it's empty as we don't want to load Flipper.
- */
-public class ReactNativeFlipper {
- public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
- // Do nothing as we don't want to initialize Flipper on Release.
- }
-}
\ No newline at end of file
diff --git a/android/build.gradle b/android/build.gradle
index 789104556b1b..c4e25dde9e2b 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -2,13 +2,11 @@
buildscript {
ext {
- buildToolsVersion = "33.0.0"
+ buildToolsVersion = "34.0.0"
minSdkVersion = 21
- compileSdkVersion = 33
- targetSdkVersion = 33
-
- // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.
- ndkVersion = "23.1.7779620"
+ compileSdkVersion = 34
+ targetSdkVersion = 34
+ ndkVersion = "25.1.8937393"
androidXCore = "1.0.2"
multiDexEnabled = true
@@ -72,3 +70,5 @@ allprojects {
}
}
}
+
+apply plugin: "com.facebook.react.rootproject"
diff --git a/android/gradle.properties b/android/gradle.properties
index 0de47ef7d184..c77d6b16f1b3 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -28,9 +28,6 @@ android.enableJetifier=true
AsyncStorage_db_size_in_MB=10
AsyncStorage_useNextStorage=true
-# Version of flipper SDK to use with React Native
-FLIPPER_VERSION=0.182.0
-
# Use this property to specify which architecture you want to build.
# You can also override it from the CLI using
# ./gradlew -PreactNativeArchitectures=x86_64
@@ -55,3 +52,5 @@ MYAPP_UPLOAD_KEY_ALIAS=ReactNativeChat-Key-Alias
# Disable Frame Processors for VisionCamera.
# We might want to re-enable them if we need QR code scanning or other frame processing features (maybe in VisionCamera V3)
disableFrameProcessors=true
+
+android.nonTransitiveRClass=false
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index 6ec1567a0f88..d11cdd907dd9 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/android/gradlew b/android/gradlew
index 5bb05716bd7f..0adc8e1a5321 100755
--- a/android/gradlew
+++ b/android/gradlew
@@ -83,10 +83,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -133,10 +131,13 @@ location of your Java installation."
fi
else
JAVACMD=java
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
@@ -144,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC3045
+ # shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
@@ -152,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC3045
+ # shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -197,6 +198,10 @@ if "$cygwin" || "$msys" ; then
done
fi
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
@@ -241,4 +246,4 @@ eval "set -- $(
tr '\n' ' '
)" '"$@"'
-exec "$JAVACMD" "$@"
\ No newline at end of file
+exec "$JAVACMD" "$@"
diff --git a/assets/animations/Coin.lottie b/assets/animations/Coin.lottie
new file mode 100644
index 000000000000..e426f7efdc3c
Binary files /dev/null and b/assets/animations/Coin.lottie differ
diff --git a/assets/emojis/index.ts b/assets/emojis/index.ts
index 5e5565da1499..02328001674e 100644
--- a/assets/emojis/index.ts
+++ b/assets/emojis/index.ts
@@ -1,10 +1,13 @@
+import type {Locale} from '@src/types/onyx';
import emojis from './common';
import enEmojis from './en';
import esEmojis from './es';
-import type {Emoji} from './types';
+import type {Emoji, EmojisList} from './types';
type EmojiTable = Record;
+type LocaleEmojis = Partial>;
+
const emojiNameTable = emojis.reduce((prev, cur) => {
const newValue = prev;
if (!('header' in cur) && cur.name) {
@@ -26,10 +29,10 @@ const emojiCodeTableWithSkinTones = emojis.reduce((prev, cur) => {
return newValue;
}, {});
-const localeEmojis = {
+const localeEmojis: LocaleEmojis = {
en: enEmojis,
es: esEmojis,
-} as const;
+};
export default emojis;
export {emojiNameTable, emojiCodeTableWithSkinTones, localeEmojis};
diff --git a/assets/emojis/types.ts b/assets/emojis/types.ts
index e8c222fde948..e659924a7fa4 100644
--- a/assets/emojis/types.ts
+++ b/assets/emojis/types.ts
@@ -3,7 +3,7 @@ import type IconAsset from '@src/types/utils/IconAsset';
type Emoji = {
code: string;
name: string;
- types?: string[];
+ types?: readonly string[];
};
type HeaderEmoji = {
@@ -12,8 +12,10 @@ type HeaderEmoji = {
code: string;
};
-type PickerEmojis = Array;
+type PickerEmoji = Emoji | HeaderEmoji;
+
+type PickerEmojis = PickerEmoji[];
type EmojisList = Record;
-export type {Emoji, HeaderEmoji, EmojisList, PickerEmojis};
+export type {Emoji, HeaderEmoji, EmojisList, PickerEmojis, PickerEmoji};
diff --git a/assets/images/new-expensify.svg b/assets/images/new-expensify.svg
index 38276ecd9385..89102ecbc5e4 100644
--- a/assets/images/new-expensify.svg
+++ b/assets/images/new-expensify.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
diff --git a/assets/images/simple-illustrations/simple-illustration__commentbubbles.svg b/assets/images/simple-illustrations/simple-illustration__commentbubbles.svg
new file mode 100644
index 000000000000..829d3ee2e3fe
--- /dev/null
+++ b/assets/images/simple-illustrations/simple-illustration__commentbubbles.svg
@@ -0,0 +1,22 @@
+
+
+
diff --git a/assets/images/simple-illustrations/simple-illustration__hourglass.svg b/assets/images/simple-illustrations/simple-illustration__hourglass.svg
new file mode 100644
index 000000000000..539e1e45b795
--- /dev/null
+++ b/assets/images/simple-illustrations/simple-illustration__hourglass.svg
@@ -0,0 +1,56 @@
+
+
+
diff --git a/assets/images/simple-illustrations/simple-illustration__trashcan.svg b/assets/images/simple-illustrations/simple-illustration__trashcan.svg
new file mode 100644
index 000000000000..4e66efa0a67e
--- /dev/null
+++ b/assets/images/simple-illustrations/simple-illustration__trashcan.svg
@@ -0,0 +1,52 @@
+
+
+
diff --git a/babel.config.js b/babel.config.js
index d8ad66917b82..0a17f2b0f01c 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -22,7 +22,7 @@ const webpack = {
};
const metro = {
- presets: [require('metro-react-native-babel-preset')],
+ presets: [require('@react-native/babel-preset')],
plugins: [
// This is needed due to a react-native bug: https://github.com/facebook/react-native/issues/29084#issuecomment-1030732709
// It is included in metro-react-native-babel-preset but needs to be before plugin-proposal-class-properties or FlatList will break
diff --git a/contributingGuides/CONTRIBUTING.md b/contributingGuides/CONTRIBUTING.md
index 6e02cae677bb..186d7def3423 100644
--- a/contributingGuides/CONTRIBUTING.md
+++ b/contributingGuides/CONTRIBUTING.md
@@ -5,7 +5,7 @@ Welcome! Thanks for checking out the New Expensify app and taking the time to co
If you would like to become an Expensify contributor, the first step is to read this document in its **entirety**. The second step is to review the README guidelines [here](https://github.com/Expensify/App/blob/main/README.md) to understand our coding philosophy and for a general overview of the code repository (i.e. how to run the app locally, testing, storage, our app philosophy, etc). Please read both documents before asking questions, as it may be covered within the documentation.
#### Test Accounts
-You can create as many accounts as needed in order to test your changes directly from [the app](https://new.expensify.com/). An initial account can be created when logging in for the first time, and additional accounts can be created by opening the "New Chat" or "Group Chat" pages via the Global Create menu, inputting a valid email or phone number, and tapping the user's avatar.
+You can create as many accounts as needed in order to test your changes directly from [the app](https://new.expensify.com/). An initial account can be created when logging in for the first time, and additional accounts can be created by opening the "New Chat" or "Group Chat" pages via the Global Create menu, inputting a valid email or phone number, and tapping the user's avatar. Do use Expensify employee or customer accounts for testing.
**Notes**:
diff --git a/contributingGuides/TS_STYLE.md b/contributingGuides/TS_STYLE.md
index b60c28147a45..b96f24a7c949 100644
--- a/contributingGuides/TS_STYLE.md
+++ b/contributingGuides/TS_STYLE.md
@@ -671,7 +671,7 @@ declare module "external-library-name" {
> This section contains instructions that are applicable during the migration.
-- 🚨 DO NOT write new code in TypeScript yet. The only time you write TypeScript code is when the file you're editing has already been migrated to TypeScript by the migration team, or when you need to add new files under `src/libs`, `src/hooks`, `src/styles`, and `src/languages` directories. This guideline will be updated once it's time for new code to be written in TypeScript. If you're doing a major overhaul or refactoring of particular features or utilities of App and you believe it might be beneficial to migrate relevant code to TypeScript as part of the refactoring, please ask in the #expensify-open-source channel about it (and prefix your message with `TS ATTENTION:`).
+- 🚨 Any new files under `src/` directory MUST be created in TypeScript now! New files in other directories (e.g. `tests/`, `desktop/`) can be created in TypeScript, if desired.
- If you're migrating a module that doesn't have a default implementation (i.e. `index.ts`, e.g. `getPlatform`), convert `index.website.js` to `index.ts`. Without `index.ts`, TypeScript cannot get type information where the module is imported.
diff --git a/desktop/main.js b/desktop/main.js
index 5ae02377e2b9..c9d614d3de15 100644
--- a/desktop/main.js
+++ b/desktop/main.js
@@ -511,6 +511,15 @@ const mainWindow = () => {
}
});
+ browserWindow.on('swipe', (e, direction) => {
+ if (direction === 'right') {
+ browserWindow.webContents.goBack();
+ }
+ if (direction === 'left') {
+ browserWindow.webContents.goForward();
+ }
+ });
+
browserWindow.on(ELECTRON_EVENTS.FOCUS, () => {
browserWindow.webContents.send(ELECTRON_EVENTS.FOCUS);
});
diff --git a/desktop/package-lock.json b/desktop/package-lock.json
index 6f62e6a5ba00..268c706bedef 100644
--- a/desktop/package-lock.json
+++ b/desktop/package-lock.json
@@ -10,7 +10,7 @@
"electron-context-menu": "^2.3.0",
"electron-log": "^4.4.8",
"electron-serve": "^1.2.0",
- "electron-updater": "^6.1.6",
+ "electron-updater": "^6.1.7",
"node-machine-id": "^1.1.12"
}
},
@@ -50,9 +50,9 @@
}
},
"node_modules/builder-util-runtime": {
- "version": "9.2.2",
- "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.2.tgz",
- "integrity": "sha512-Or2/ycVYRGQ876hKMfiz2Ghgzh3WllgPW75jqt1Ta2a5wprpnziFrHpQ9eUq6/ScsVXMnG4PmQqlMsE9NFg8DQ==",
+ "version": "9.2.3",
+ "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.3.tgz",
+ "integrity": "sha512-FGhkqXdFFZ5dNC4C+yuQB9ak311rpGAw+/ASz8ZdxwODCv1GGMWgLDeofRkdi0F3VCHQEWy/aXcJQozx2nOPiw==",
"dependencies": {
"debug": "^4.3.4",
"sax": "^1.2.4"
@@ -156,11 +156,11 @@
}
},
"node_modules/electron-updater": {
- "version": "6.1.6",
- "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.1.6.tgz",
- "integrity": "sha512-G2bO72i7kv+bVdBAjq6lQn8zkZ3wMRRjxBD4TGBjB77UiuMDUBeP45YAs4y08udPzttGW2qzpnbOUJY5RYWZfw==",
+ "version": "6.1.7",
+ "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.1.7.tgz",
+ "integrity": "sha512-SNOhYizjkm4ET+Y8ilJyUzcVsFJDtINzVN1TyHnZeMidZEG3YoBebMyXc/J6WSiXdUaOjC7ngekN6rNp6ardHA==",
"dependencies": {
- "builder-util-runtime": "9.2.2",
+ "builder-util-runtime": "9.2.3",
"fs-extra": "^10.1.0",
"js-yaml": "^4.1.0",
"lazy-val": "^1.0.5",
@@ -467,9 +467,9 @@
"integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ=="
},
"builder-util-runtime": {
- "version": "9.2.2",
- "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.2.tgz",
- "integrity": "sha512-Or2/ycVYRGQ876hKMfiz2Ghgzh3WllgPW75jqt1Ta2a5wprpnziFrHpQ9eUq6/ScsVXMnG4PmQqlMsE9NFg8DQ==",
+ "version": "9.2.3",
+ "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.3.tgz",
+ "integrity": "sha512-FGhkqXdFFZ5dNC4C+yuQB9ak311rpGAw+/ASz8ZdxwODCv1GGMWgLDeofRkdi0F3VCHQEWy/aXcJQozx2nOPiw==",
"requires": {
"debug": "^4.3.4",
"sax": "^1.2.4"
@@ -541,11 +541,11 @@
"integrity": "sha512-zJG3wisMrDn2G/gnjrhyB074COvly1FnS0U7Edm8bfXLB8MYX7UtwR9/y2LkFreYjzQHm9nEbAfgCmF+9M9LHQ=="
},
"electron-updater": {
- "version": "6.1.6",
- "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.1.6.tgz",
- "integrity": "sha512-G2bO72i7kv+bVdBAjq6lQn8zkZ3wMRRjxBD4TGBjB77UiuMDUBeP45YAs4y08udPzttGW2qzpnbOUJY5RYWZfw==",
+ "version": "6.1.7",
+ "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.1.7.tgz",
+ "integrity": "sha512-SNOhYizjkm4ET+Y8ilJyUzcVsFJDtINzVN1TyHnZeMidZEG3YoBebMyXc/J6WSiXdUaOjC7ngekN6rNp6ardHA==",
"requires": {
- "builder-util-runtime": "9.2.2",
+ "builder-util-runtime": "9.2.3",
"fs-extra": "^10.1.0",
"js-yaml": "^4.1.0",
"lazy-val": "^1.0.5",
diff --git a/desktop/package.json b/desktop/package.json
index 7545e4b57dba..563a45851eb2 100644
--- a/desktop/package.json
+++ b/desktop/package.json
@@ -7,7 +7,7 @@
"electron-context-menu": "^2.3.0",
"electron-log": "^4.4.8",
"electron-serve": "^1.2.0",
- "electron-updater": "^6.1.6",
+ "electron-updater": "^6.1.7",
"node-machine-id": "^1.1.12"
},
"author": "Expensify, Inc.",
diff --git a/docs/articles/expensify-classic/account-settings/Account-Details.md b/docs/articles/expensify-classic/account-settings/Account-Details.md
index bc4b94bf8a51..535e74eeb701 100644
--- a/docs/articles/expensify-classic/account-settings/Account-Details.md
+++ b/docs/articles/expensify-classic/account-settings/Account-Details.md
@@ -60,10 +60,12 @@ Is your Secondary Login (personal email) invalidated in your company account? If
4. Head to your personal email account and follow the prompts
5. You'll receive a link in the email to click that will unlink the two accounts
-# FAQ
+{% include faq-begin.md %}
## The profile picture on my account updated automatically. Why did this happen?
Our focus is always on making your experience user-friendly and saving you valuable time. One of the ways we achieve this is by utilizing a public API to retrieve public data linked to your email address.
This tool searches for public accounts or profiles associated with your email address, such as on LinkedIn. When it identifies one, it pulls in the uploaded profile picture and name to Expensify.
While this automated process is generally accurate, there may be instances where it's not entirely correct. If this happens, we apologize for any inconvenience caused. The good news is that rectifying such situations is a straightforward process. You can quickly update your information manually by following the directions provided above, ensuring your data is accurate and up to date in no time.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/account-settings/Close-Account.md b/docs/articles/expensify-classic/account-settings/Close-Account.md
index c25c22de9704..9b1e886fc94a 100644
--- a/docs/articles/expensify-classic/account-settings/Close-Account.md
+++ b/docs/articles/expensify-classic/account-settings/Close-Account.md
@@ -114,10 +114,12 @@ Here's how to do it:
By following these steps, you can easily verify your email or phone number and close an unwanted Expensify account.
-# FAQ
+{% include faq-begin.md %}
## What should I do if I'm not directed to my account when clicking the validate option from my phone or email?
It's possible your browser has blocked this, either because of some existing cache or extension. In this case, you should follow the Reset Password flow to reset the password and manually gain access with the new password, along with your email address.
## Why don't I see the Close Account option?
It's possible your account is on a managed company domain. In this case, only the admins from that company can close it.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/account-settings/Copilot.md b/docs/articles/expensify-classic/account-settings/Copilot.md
index 4fac402b7ced..31bc0eff60e6 100644
--- a/docs/articles/expensify-classic/account-settings/Copilot.md
+++ b/docs/articles/expensify-classic/account-settings/Copilot.md
@@ -59,7 +59,7 @@ To ensure a receipt is routed to the Expensify account in which you are a copilo
3. Send
-# FAQ
+{% include faq-begin.md %}
## Can a Copilot's Secondary Login be used to forward receipts?
Yes! A Copilot can use any of the email addresses tied to their account to forward receipts into the account of the person they're assisting.
@@ -67,3 +67,5 @@ Yes! A Copilot can use any of the email addresses tied to their account to forwa
No, only the original account holder can add another Copilot to the account.
## Is there a restriction on the number of Copilots I can have or the number of users for whom I can act as a Copilot?
There is no limit! You can have as many Copilots as you like, and you can be a Copilot for as many users as you need.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/account-settings/Merge-Accounts.md b/docs/articles/expensify-classic/account-settings/Merge-Accounts.md
index abb218c74118..34bf422aa983 100644
--- a/docs/articles/expensify-classic/account-settings/Merge-Accounts.md
+++ b/docs/articles/expensify-classic/account-settings/Merge-Accounts.md
@@ -19,7 +19,7 @@ Merging two accounts together is fairly straightforward. Let’s go over how to
8. Paste the code into the required field
If you have any questions about this process, feel free to reach out to Concierge for some assistance!
-# FAQ
+{% include faq-begin.md %}
## Can you merge accounts from the mobile app?
No, accounts can only be merged from the full website at expensify.com.
## Can I administratively merge two accounts together?
@@ -34,3 +34,5 @@ Yes! Please see below:
- If you have two accounts with two different verified domains, you cannot merge them together.
## What happens to my “personal” Individual workspace when merging accounts?
The old “personal” Individual workspace is deleted. If you plan to submit reports under a different workspace in the future, ensure that any reports on the Individual workspace in the old account are marked as Open before merging the accounts. You can typically do this by selecting “Undo Submit” on any submitted reports.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/International-Reimbursements.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Global-Reimbursements.md
similarity index 96%
rename from docs/articles/expensify-classic/bank-accounts-and-credit-cards/International-Reimbursements.md
rename to docs/articles/expensify-classic/bank-accounts-and-credit-cards/Global-Reimbursements.md
index 7313c73ac6e6..2ff74760b376 100644
--- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/International-Reimbursements.md
+++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Global-Reimbursements.md
@@ -75,11 +75,11 @@ Examples of additional requested information:
- An authorization letter
- An independently certified documentation such as shareholder agreement from a lawyer, notary, or public accountant if an individual owns more than 25% of the company
-# FAQ
+{% include faq-begin.md %}
## How many people can send reimbursements internationally?
-Once your company is authorized to send global payments, only the individual who went through the verification can reimburse international employees.
+Once your company is authorized to send global payments, the individual who verified the bank account can share it with additional admins on the workspace. That way, multiple workspace members can send international reimbursements.
## How long does it take to verify an account for international payments?
@@ -103,3 +103,4 @@ This is the person who will process international reimbursements. The authorized
You can leave this form section blank since the “User” is Expensify.
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Personal-Credit-Cards.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Personal-Credit-Cards.md
index c41178b4aa7f..05149ebf868e 100644
--- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Personal-Credit-Cards.md
+++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/Personal-Credit-Cards.md
@@ -59,7 +59,7 @@ Expenses can be imported as either reimbursable or non-reimbursable. Select the
*Remove a card*: If you need to remove a card, you can select the red trash can icon. Please remember this will remove all unreported and un-submitted transactions from your account that are tied to this card, so be careful!
-# FAQ
+{% include faq-begin.md %}
*Is the bank/credit card import option right for me?*
If you incur expenses using your personal or business card and need to get them accounted for in your company’s accounting, then you might want to import your bank/credit card. Please note, if you have a company-assigned corporate card, check with your company's Expensify admin on how to handle these cards. Often, admins will take care of card assignments, and you won't need to import them yourself.
@@ -74,3 +74,5 @@ If you aren't able to see the expenses imported when you click “View expenses
*How do I remove an imported spreadsheet?*
If you need to remove an imported spreadsheet, you can select the red trash can icon. Please remember this will remove all unreported and unsubmitted transactions from your account that are tied to this import, so be careful!
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/business-bank-accounts/Business-Bank-Accounts-AUD.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/business-bank-accounts/Business-Bank-Accounts-AUD.md
index b59f68a65ce6..8c5ead911da4 100644
--- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/business-bank-accounts/Business-Bank-Accounts-AUD.md
+++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/business-bank-accounts/Business-Bank-Accounts-AUD.md
@@ -36,7 +36,7 @@ You can complete this process either via the web app (on a computer), or via the
If you are new to using Batch Payments in Australia, to reimburse your staff or process payroll, you may want to check out these bank-specific instructions for how to upload your .aba file:
- ANZ Bank - [Import a file for payroll payments](https://www.anz.com.au/support/internet-banking/pay-transfer-business/payroll/import-file/)
-- CommBank - [Importing and using Direct Entry (EFT) files](https://www.commbank.com.au/business/pds/003-279-importing-a-de-file.pdf)
+- CommBank - [Importing and using Direct Entry (EFT) files](https://www.commbank.com.au/business/pds/003-279-importing-a-de-file.pdf)
- Westpac - [Importing Payment Files](https://www.westpac.com.au/business-banking/online-banking/support-faqs/import-files/)
- NAB - [Quick Reference Guide - Upload a payment file](https://www.nab.com.au/business/online-banking/nab-connect/help)
- Bendigo Bank - [Bulk payments user guide](https://www.bendigobank.com.au/globalassets/documents/business/bulk-payments-user-guide.pdf)
diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/business-bank-accounts/Business-Bank-Accounts-USD.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/business-bank-accounts/Business-Bank-Accounts-USD.md
index 2fbdac02e85c..4ae2c669561f 100644
--- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/business-bank-accounts/Business-Bank-Accounts-USD.md
+++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/business-bank-accounts/Business-Bank-Accounts-USD.md
@@ -127,7 +127,7 @@ If you get a generic error message that indicates, "Something's gone wrong", ple
8. If you have another phone available, try to follow these steps on that device
If the issue persists, please contact your Account Manager or Concierge for further troubleshooting assistance.
-# FAQ
+{% include faq-begin.md %}
## What is a Beneficial Owner?
A Beneficial Owner refers to an **individual** who owns 25% or more of the business. If no individual owns 25% or more of the business, the company does not have a Beneficial Owner.
@@ -157,3 +157,5 @@ It's a good idea to wait till the end of that second business day. If you still
Make sure to reach out to your Account Manager or to Concierge once you have done so and our team will be able to re-trigger those 3 transactions!
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/CSV-Import.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/CSV-Import.md
index fc1e83701caf..fd50c245d568 100644
--- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/CSV-Import.md
+++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/CSV-Import.md
@@ -93,9 +93,11 @@ Then, try to upload the revised spreadsheet again:
3. Check the row count again on the Output Preview to confirm it matches the spreadsheet
4. Click **Submit Spreadsheet**
-# FAQ
+{% include faq-begin.md %}
## Why can't I see my CSV transactions immediately after uploading them?
Don't worry! You'll typically need to wait 1-2 minutes after clicking **I understand, I'll wait!**
## I'm trying to import a credit. Why isn't it uploading?
Negative expenses shouldn't include a minus sign. Instead, they should just be wrapped in parentheses. For example, to indicate "-335.98," you'll want to make sure it's formatted as "(335.98)."
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Commercial-Card-Feeds.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Commercial-Card-Feeds.md
index a60c1ab7831a..f46c1a1442c2 100644
--- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Commercial-Card-Feeds.md
+++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Commercial-Card-Feeds.md
@@ -99,7 +99,7 @@ To completely remove the card connection, unassign every card from the list and
Note: If expenses are Processing and then rejected, they will also be deleted when they're returned to an Open state as the card they're linked to no longer exists.
-# FAQ
+{% include faq-begin.md %}
## My Commercial Card feed is set up. Why is a specific card not coming up when I try to assign it to an employee?
Cards will appear in the drop-down when activated and have at least one posted transaction. If the card is activated and has been used for a while and you're still not seeing it, please reach out to your Account Manager or message concierge@expensify.com for further assistance.
@@ -124,3 +124,5 @@ If your company uses a Commercial Card program that isn’t with one of our Appr
- Stripe
- Brex
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Company-Card-Settings.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Company-Card-Settings.md
index fa5879d85ea8..bc9801060223 100644
--- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Company-Card-Settings.md
+++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Company-Card-Settings.md
@@ -84,8 +84,10 @@ Expensify eReceipts serve as digital substitutes for paper receipts in your purc
To ensure seamless automatic importation, it's essential to maintain your transactions in US Dollars. Additionally, eReceipts can be directly imported from your bank account. Please be aware that CSV/OFX imported files of bank transactions do not support eReceipts.
It's important to note that eReceipts are not generated for lodging expenses. Moreover, due to incomplete or inaccurate category information from certain banks, there may be instances of invalid eReceipts being generated for hotel purchases. If you choose to re-categorize expenses, a similar situation may arise. It's crucial to remember that our Expensify eReceipt Guarantee excludes coverage for hotel and motel expenses.
-# FAQ
+{% include faq-begin.md %}
## What plan/subscription is required in order to manage corporate cards?
Group Policy (Collect or Control plan only)
## When do my company card transactions import to Expensify?
Credit card transactions are imported to Expensify once they’re posted to the bank account. This usually takes 1-3 business days between the point of purchase and when the transactions populate in your account.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Connect-ANZ.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Connect-ANZ.md
index 59104ce36a41..9844622f8539 100644
--- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Connect-ANZ.md
+++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Connect-ANZ.md
@@ -24,7 +24,7 @@ Importing your ANZ Visa into Expensify will allow your card transactions to flow
4. Once you’ve filled out and submitted your Internet Banking data authority form or ANZ Direct Online authority form, ANZ will set up the feed and send all the details directly to Expensify.
5. Then, we’ll add the card feed to your Expensify account and send you a message to let you know that it has been set up. We'll also include some webinar training resources to ensure you have all the information you need!
-# FAQ
+{% include faq-begin.md %}
## Are there discounts available for ANZ customers?
As ANZ’s preferred receipt tracking and expense management partner, Expensify offers ANZ business customers a few special perks:
@@ -44,3 +44,5 @@ After the free trial, you’ll get preferred pricing at 50% off the current rate
## Do I need to sign up for a specific period in order to receive the discount?
There is no obligation to sign up for a certain period to receive the discount. After your free trial, the 50% discount for the first 12 months, will be applied automatically to your account. After the initial 12 months, the 15% discount will also be applied automatically.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Direct-Bank-Connections.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Direct-Bank-Connections.md
index 372edd8f14ec..c9720177a8fc 100644
--- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Direct-Bank-Connections.md
+++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Direct-Bank-Connections.md
@@ -72,7 +72,7 @@ If you need to connect a separate card program from the same bank (that's access
To fix this, you would need to contact your bank and request to combine all of your cards under a single set of login credentials. That way, you can connect all of your cards from that bank to Expensify using a single set of login credentials.
-# FAQ
+{% include faq-begin.md %}
## How can I connect and manage my company’s cards centrally if I’m not a domain admin?
If you cannot access Domains, you must request Domain Admin access to an existing Domain Admin (usually the workspace owner).
@@ -112,3 +112,5 @@ If you've answered "yes" to any of these questions, you'll need to update this i
A Domain Admin can fix the connection by heading to **Settings > Domains > _Domain Name_ > Company Cards > Fix**. You will be prompted to enter the new credentials/updated information, and this should reestablish the connection.
If you are still experiencing issues with the card connection, please search for company card troubleshooting or contact Expensify Support for help.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Export-To-GL-Accounts.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Export-To-GL-Accounts.md
deleted file mode 100644
index 85b534338b53..000000000000
--- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Export-To-GL-Accounts.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Export to GL Accounts
-description: Export to GL Accounts
----
-## Resource Coming Soon!
diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Reconciliation.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Reconciliation.md
index d6de2ca66ade..2cb684a2240b 100644
--- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Reconciliation.md
+++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Reconciliation.md
@@ -51,7 +51,7 @@ If there are still unapproved expenses when you want to close your books for the
- Match Approved Total to Company Card Liability account in your accounting system.
- Unapproved Total becomes the Accrual amount (provided the first two amounts are correct).
-# FAQ
+{% include faq-begin.md %}
## Who can view and access the Reconciliation tab?
@@ -67,3 +67,5 @@ If a cardholder reports expenses as missing, we first recommend using the Reconc
If after updating, the expense still hasn’t appeared, you should reach out to Concierge with the missing expense specifics (merchant, date, amount and last four digits of the card number). Please note, only posted transactions will import.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-USD.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-USD.md
index a4ff7503f7bb..0bc5cb0ad955 100644
--- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-USD.md
+++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/deposit-accounts/Deposit-Accounts-USD.md
@@ -56,7 +56,7 @@ You should be all set! The bank account will display as a deposit-only business
1. Navigate to **Settings > Account > Payments > Bank Accounts**
2. Click the **Delete** next to the bank account you want to remove
-# FAQ
+{% include faq-begin.md %}
## **What happens if my bank requires an additional security check before adding it to a third-party?**
@@ -73,3 +73,5 @@ There are a few reasons a reimbursement may be unsuccessful. The first step is t
- 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/docs/articles/expensify-classic/billing-and-subscriptions/Billing-Overview.md b/docs/articles/expensify-classic/billing-and-subscriptions/Billing-Overview.md
index 30a507a1f9df..09dd4de2867b 100644
--- a/docs/articles/expensify-classic/billing-and-subscriptions/Billing-Overview.md
+++ b/docs/articles/expensify-classic/billing-and-subscriptions/Billing-Overview.md
@@ -26,7 +26,7 @@ If at least 50% of your approved USD spend in a given month is on your company
Additionally, every month, you receive 1% cash back on all Expensify Card purchases, and 2% if the spend across your Expensify Cards is $250k or more. Any cash back from the Expensify Card is first applied to your Expensify bill, further reducing your price per member. Any leftover cash back is deposited directly into your connected bank account.
## Savings calculator
To see how much money you can save (and even earn!) by using the Expensify Card, check out our [savings calculator](https://use.expensify.com/price-savings-calculator). Just enter a few details and see how much you’ll save!
-# FAQ
+{% include faq-begin.md %}
## What if we put less than 50% of our total spend on the Expensify Card?
If you put less than 50% of your total USD spend on your Expensify Card, your bill gets discounted on a sliding scale based on the percentage of use. So if you don't use the Expensify Card at all, you'll be charged the full rate for each member based on your plan and subscription.
Example:
@@ -36,3 +36,5 @@ Example:
You save 70% on the price per member on your bill for that month.
Note: USD spend refers to approved USD transactions on the Expensify Card in any given month, compared to all approved USD spend on workspaces in that same month.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Billing-Owner.md b/docs/articles/expensify-classic/billing-and-subscriptions/Billing-Owner.md
index 4fd7ef71c2e7..49a369c3cb51 100644
--- a/docs/articles/expensify-classic/billing-and-subscriptions/Billing-Owner.md
+++ b/docs/articles/expensify-classic/billing-and-subscriptions/Billing-Owner.md
@@ -38,7 +38,7 @@ To take over billing for the entire domain, you must:
1. Go to **Settings > Domains > _Domain Name_ > Domain Admins** and enable Consolidated Domain Billing.
Currently, Consolidated Domain Billing simply consolidates the amounts due for each Group Workspace Billing Owner (listed on the **Settings > Workspaces > Group** page). If you want to use the Annual Subscription across all Workspaces on the domain, you must also be the Billing Owner of all Group Workspaces.
-# FAQ
+{% include faq-begin.md %}
## Why can't I see the option to take over billing?
There could be two reasons:
1. You may not have the role of Workspace Admin. If you can't click on the Workspace name (if it's not a blue hyperlink), you're not a Workspace Admin. Another Workspace Admin for that Workspace must change your role before you can proceed.
@@ -47,3 +47,5 @@ There could be two reasons:
There are two ways to resolve this:
1. Have your IT dept. gain access to the account so that you can make yourself an admin. Your IT department may need to recreate the ex-employee's email address. Once your IT department has access to the employee's Home page, you can request a magic link to be sent to that email address to gain access to the account.
1. Have another admin make you a Workspace admin.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Change-Plan-Or-Subscription.md b/docs/articles/expensify-classic/billing-and-subscriptions/Change-Plan-Or-Subscription.md
index f01bb963bacf..1e631a53b0b3 100644
--- a/docs/articles/expensify-classic/billing-and-subscriptions/Change-Plan-Or-Subscription.md
+++ b/docs/articles/expensify-classic/billing-and-subscriptions/Change-Plan-Or-Subscription.md
@@ -76,9 +76,11 @@ Note: Refunds apply to Collect or Control Group Workspaces with one month of bil
Once you’ve successfully downgraded to a free Expensify account, your Workspace will be deleted and you will see a refund line item added to your Billing History.
-# FAQ
+{% include faq-begin.md %}
## Will I be charged for a monthly subscription even if I don't use SmartScans?
Yes, the Monthly Subscription is prepaid and not based on activity, so you'll be charged regardless of usage.
## I'm on a group policy; do I need the monthly subscription too?
Probably not. Group policy members already have unlimited SmartScans, so there's usually no need to buy the subscription. However, you can use it for personal use if you leave your company's Workspace.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Consolidated-Domain-Billing.md b/docs/articles/expensify-classic/billing-and-subscriptions/Consolidated-Domain-Billing.md
index 35f6a428e0af..2e829c0785d3 100644
--- a/docs/articles/expensify-classic/billing-and-subscriptions/Consolidated-Domain-Billing.md
+++ b/docs/articles/expensify-classic/billing-and-subscriptions/Consolidated-Domain-Billing.md
@@ -16,8 +16,10 @@ When a Domain Admin enables Consolidated Domain Billing, all Group workspaces ow
If you don’t have multiple billing owners across your organization, or if you want to keep billing separate for any reason, then this feature isn’t necessary.
If you have an Annual Subscription and enable Consolidated Domain Billing, the Consolidated Domain Billing feature will gather the amounts due for each Group workspace Billing Owner (listed under **Settings > Workspaces > Group**). To make full use of the Annual Subscription for all workspaces in your domain, you should also be the billing owner for all Group workspaces.
-# FAQ
+{% include faq-begin.md %}
## How do I take over the billing of a workspace with Consolidated Domain Billing enabled?
You’ll have to toggle off Consolidated Domain Billing, take over ownership of the workspace, and then toggle it back on.
## Can I use Consolidated Domain Billing to cover the bill for some workspaces, but not others?
No, this feature means that you’ll be paying the bill for all domain members who choose a subscription.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Free-Trial.md b/docs/articles/expensify-classic/billing-and-subscriptions/Free-Trial.md
index 4f660588d432..e6d8f2fedb73 100644
--- a/docs/articles/expensify-classic/billing-and-subscriptions/Free-Trial.md
+++ b/docs/articles/expensify-classic/billing-and-subscriptions/Free-Trial.md
@@ -31,7 +31,7 @@ To access these extra free weeks, all you need to do is complete the tasks on yo
- Establish a connection between Expensify and your accounting system from the outset. By doing this early, you can start testing Expensify comprehensively from end to end.
-# FAQ
+{% include faq-begin.md %}
## What happens when my Free Trial ends?
If you’ve already added a billing card to Expensify, you will automatically start your organization’s Expensify subscription after your Free Trial ends. At the beginning of the following month, we'll bill the card you have on file for your subscription, adjusting the charge to exclude the Free Trial period.
If your Free Trial concludes without a billing card on file, you will see a notification on your Home page saying, 'Your Free Trial has expired.'
@@ -42,3 +42,5 @@ If you continue without adding a billing card, you will be granted a five-day gr
If you’d like to downgrade to an individual account after your Free Trial has ended, you will need to delete any Group Workspace that you have created. This action will remove the Workspaces, subscription, and any amount owed. You can do this in one of two ways from the Expensify web app:
- Select the “Downgrade” option on the billing card task on your Home page.
- Go to **Settings > Workspaces > [Workspace name]**, then click the gear button next to the Workspace and select Delete.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Individual-Subscription.md b/docs/articles/expensify-classic/billing-and-subscriptions/Individual-Subscription.md
index aa08340dd7a6..1d952cb15b1c 100644
--- a/docs/articles/expensify-classic/billing-and-subscriptions/Individual-Subscription.md
+++ b/docs/articles/expensify-classic/billing-and-subscriptions/Individual-Subscription.md
@@ -48,7 +48,7 @@ After purchasing the subscription from the App Store, remember to sync your app
The subscription renewal date is the same as the purchase date. For instance, if you sign up for the subscription on September 7th, it will renew automatically on October 7th. You can cancel your subscription anytime during the month if you no longer need unlimited SmartScans. If you do cancel, keep in mind that your subscription (and your ability to SmartScan) will continue until the last day of the billing cycle.
-# FAQ
+{% include faq-begin.md %}
## Can I use an Individual Subscription while on a Collect or Control Plan?
You can! If you want to track expenses separately from your organization’s Workspace, you can sign up for an Individual Subscription. However, only Submit and Track Workspace plans are available when on an Individual Subscription. Collect and Control Workspace plans require an annual or pay-per-use subscription. For more information, visit expensify.com/pricing.
@@ -65,3 +65,5 @@ Your subscription is a pre-purchase for 30 days of unlimited SmartScanning. This
## How can I cancel my subscription from the iOS app?
If you signed up for the Monthly Subscription via iOS and your iTunes account, you will need to log into iTunes and locate the subscription there in order to cancel it. The ability to cancel an Expensify subscription started via iOS is strictly limited to your iTunes account.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Pay-Per-Use-Subscription.md b/docs/articles/expensify-classic/billing-and-subscriptions/Pay-Per-Use-Subscription.md
index 2133e8c7da46..326ce7fe33ab 100644
--- a/docs/articles/expensify-classic/billing-and-subscriptions/Pay-Per-Use-Subscription.md
+++ b/docs/articles/expensify-classic/billing-and-subscriptions/Pay-Per-Use-Subscription.md
@@ -11,7 +11,7 @@ Pay-per-use is a billing option for people who prefer to use Expensify month to
1. Create a Group Workspace if you haven’t already by going to **Settings > Workspaces > Group > New Workspace**
2. Once you’ve created your Workspace, under the “Subscription” section on the Group Workspace page, select “Pay-per-use”.
-# FAQ
+{% include faq-begin.md %}
## What is considered an active user?
An active user is anyone who chats, creates, modifies, submits, approves, reimburses, or exports a report in Expensify. This includes actions taken by a Copilot and Workspace automation (such as Scheduled Submit and automated reimbursement). If no one on your Group Workspace uses Expensify in a given month, you will not be billed for that month.
@@ -26,4 +26,4 @@ If you expect to have an increased number of users for more than 3 out of 12 mon
## Will billing only be in USD currency?
While USD is the default billing currency, we also have GBP, AUD, and NZD billing currencies. You can see the rates on our [pricing](https://www.expensify.com/pricing) page.
-
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Tax-Exempt.md b/docs/articles/expensify-classic/billing-and-subscriptions/Tax-Exempt.md
index 33fbec003a91..92c92e4e3a44 100644
--- a/docs/articles/expensify-classic/billing-and-subscriptions/Tax-Exempt.md
+++ b/docs/articles/expensify-classic/billing-and-subscriptions/Tax-Exempt.md
@@ -15,6 +15,8 @@ Once your account is marked as tax-exempt, the corresponding state tax will no l
If you need to remove your tax-exempt status, let your Account Manager know or contact Concierge.
-# FAQ
+{% include faq-begin.md %}
## What happens to my past Expensify bills that incorrectly had tax added to them?
Expensify can provide a refund for the tax you were charged on your previous bills. Please let your Account Manager know or contact Concierge if this is the case.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/expense-and-report-features/Attendee-Tracking.md b/docs/articles/expensify-classic/expense-and-report-features/Attendee-Tracking.md
index 7f3d83af1e6e..a0bd2c442dbb 100644
--- a/docs/articles/expensify-classic/expense-and-report-features/Attendee-Tracking.md
+++ b/docs/articles/expensify-classic/expense-and-report-features/Attendee-Tracking.md
@@ -20,7 +20,7 @@ Every expense has an Attendees field and will list the expense creator’s name
![image of an expense with attendee tracking]({{site.url}}/assets/images/attendee-tracking.png){:width="100%"}
-# FAQ
+{% include faq-begin.md %}
## Can I turn off attendee tracking?
Attendee tracking is a standard field on all expenses and cannot be turned off.
@@ -49,3 +49,4 @@ There is no limit.
## How can I remove attendees from an expense?
You can add or remove attendees from an expense as long as they are on a Draft report. Expenses on submitted reports cannot be edited, so you cannot remove attendees from these.
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/expense-and-report-features/Currency.md b/docs/articles/expensify-classic/expense-and-report-features/Currency.md
index eb6ca9bb2d40..77b5fbbb3ebc 100644
--- a/docs/articles/expensify-classic/expense-and-report-features/Currency.md
+++ b/docs/articles/expensify-classic/expense-and-report-features/Currency.md
@@ -46,7 +46,7 @@ Then, set the default currency for that workspace to match the currency in which
For example, if you have employees in the US, France, Japan, and India, you’d want to create four separate workspaces, add the employees to each, and then set the corresponding currency for each workspace.
-# FAQ
+{% include faq-begin.md %}
## I have expenses in several different currencies. How will this show up on a report?
@@ -60,5 +60,4 @@ Expenses entered in a foreign currency are automatically converted to the defaul
If you want to bypass the exchange rate conversion, you can manually enter an expense in your default currency instead.
-
-
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/expense-and-report-features/Expense-Rules.md b/docs/articles/expensify-classic/expense-and-report-features/Expense-Rules.md
index ae6a9ca77db1..295aa8d00cc9 100644
--- a/docs/articles/expensify-classic/expense-and-report-features/Expense-Rules.md
+++ b/docs/articles/expensify-classic/expense-and-report-features/Expense-Rules.md
@@ -45,11 +45,11 @@ In general, your expense rules will be applied in order, from **top to bottom**,
4. If you belong to a workspace that is tied to an accounting integration, the configuration settings for this connection may update your expense details upon export, even if the expense rules were successfully applied to the expense.
-# FAQ
+{% include faq-begin.md %}
## How can I use Expense Rules to vendor match when exporting to an accounting package?
When exporting non-reimbursable expenses to your connected accounting package, the payee field will list "Credit Card Misc." if the merchant name on the expense in Expensify is not an exact match to a vendor in the accounting package.
When an exact match is unavailable, "Credit Card Misc." prevents multiple variations of the same vendor (e.g., Starbucks and Starbucks #1234, as is often seen in credit card statements) from being created in your accounting package.
For repeated expenses, the best practice is to use Expense Rules, which will automatically update the merchant name without having to do it manually each time.
This only works for connections to QuickBooks Online, Desktop, and Xero. Vendor matching cannot be performed in this manner for NetSuite or Sage Intacct due to limitations in the API of the accounting package.
-
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/expense-and-report-features/Expense-Types.md b/docs/articles/expensify-classic/expense-and-report-features/Expense-Types.md
index 795a895e81f0..9d19dbb4f9ba 100644
--- a/docs/articles/expensify-classic/expense-and-report-features/Expense-Types.md
+++ b/docs/articles/expensify-classic/expense-and-report-features/Expense-Types.md
@@ -26,7 +26,7 @@ Each report will show the total amount for all expenses in the upper right. Unde
- **Time Expenses:** Employees or jobs are billed based on an hourly rate that you can set within Expensify.
- **Distance Expenses:** These expenses are related to travel for work.
-# FAQ
+{% include faq-begin.md %}
## What’s the difference between a receipt, an expense, and a report attachment?
@@ -40,3 +40,5 @@ In Expensify, a credit is displayed as an expense with a minus (ex. -$1.00) in f
If a report includes a credit or a refund expense, it will offset the total amount on the report.
For example, the report has two reimbursable expenses, $400 and $500. The total Reimbursable is $900.
Conversely, a -$400 and $500 will be a total Reimbursable amount of $500
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/expense-and-report-features/Report-Audit-Log-and-Comments.md b/docs/articles/expensify-classic/expense-and-report-features/Report-Audit-Log-and-Comments.md
index 229ca4ec1fe4..04183608e3d1 100644
--- a/docs/articles/expensify-classic/expense-and-report-features/Report-Audit-Log-and-Comments.md
+++ b/docs/articles/expensify-classic/expense-and-report-features/Report-Audit-Log-and-Comments.md
@@ -49,7 +49,7 @@ Report comments initially trigger a mobile app notification to report participan
Comments can be formatted with bold, italics, or strikethrough using basic Markdown formatting. You can also add receipts and supporting documents to a report by clicking the paperclip icon on the right side of the comment field.
-# FAQ
+{% include faq-begin.md %}
## Why don’t some timestamps in Expensify match up with what’s shown in the report audit log?
@@ -58,3 +58,5 @@ While the audit log is localized to your own timezone, some other features in Ex
## Is commenting on a report a billable action?
Yes. If you comment on a report, you become a billable actor for the current month.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/expense-and-report-features/The-Expenses-Page.md b/docs/articles/expensify-classic/expense-and-report-features/The-Expenses-Page.md
index 5431355dd790..57a7f7de298c 100644
--- a/docs/articles/expensify-classic/expense-and-report-features/The-Expenses-Page.md
+++ b/docs/articles/expensify-classic/expense-and-report-features/The-Expenses-Page.md
@@ -55,7 +55,7 @@ Select the expenses you want to export by checking the box to the left of each e
Then, click **Export To** in the upper right corner of the page, and choose our default CSV format or create your own custom CSV template.
-# FAQ
+{% include faq-begin.md %}
## Can I use the filters and analytics features on the mobile app?
The various features on the Expenses Page are only available while logged into your web account.
@@ -71,3 +71,4 @@ We have more about company card expense reconciliation in this [support article]
## Can I edit multiple expenses at once?
Yes! Select the expenses you want to edit and click **Edit Multiple**.
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/expense-and-report-features/The-Reports-Page.md b/docs/articles/expensify-classic/expense-and-report-features/The-Reports-Page.md
index ff9e2105ffac..9c55cd9b4b8d 100644
--- a/docs/articles/expensify-classic/expense-and-report-features/The-Reports-Page.md
+++ b/docs/articles/expensify-classic/expense-and-report-features/The-Reports-Page.md
@@ -31,7 +31,7 @@ To export a report to a CSV file, follow these steps on the Reports page:
2. Navigate to the upper right corner of the page and click the "Export to" button.
3. From the drop-down options that appear, select your preferred export format.
-# FAQ
+{% include faq-begin.md %}
## What does it mean if the integration icon for a report is grayed out?
If the integration icon for a report appears grayed out, the report has yet to be fully exported.
To address this, consider these options:
@@ -41,3 +41,4 @@ To address this, consider these options:
## How can I see a specific expense on a report?
To locate a specific expense within a report, click on the Report from the Reports page and then click on an expense to view the expense details.
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/expensify-card/Admin-Card-Settings-and-Features.md b/docs/articles/expensify-classic/expensify-card/Admin-Card-Settings-and-Features.md
index 1bfa5590efbc..16e628acbeee 100644
--- a/docs/articles/expensify-classic/expensify-card/Admin-Card-Settings-and-Features.md
+++ b/docs/articles/expensify-classic/expensify-card/Admin-Card-Settings-and-Features.md
@@ -148,7 +148,7 @@ Here are some reasons an Expensify Card transaction might be declined:
5. The merchant is located in a restricted country
- Some countries may be off-limits for transactions. If a merchant or their headquarters (billing address) are physically located in one of these countries, Expensify Card purchases will be declined. This list may change at any time, so be sure to check back frequently: Belarus, Burundi, Cambodia, Central African Republic, Democratic Republic of the Congo, Cuba, Iran, Iraq, North Korea, Lebanon, Libya, Russia, Somalia, South Sudan, Syrian Arab Republic, Tanzania, Ukraine, Venezuela, Yemen, and Zimbabwe.
-# FAQ
+{% include faq-begin.md %}
## What happens when I reject an Expensify Card expense?
Rejecting an Expensify Card expense from an Expensify report will simply allow it to be reported on a different report.
@@ -170,3 +170,5 @@ If a transaction is pending and has a receipt attached (excluding eReceipts), a
- Partial refunds:
If a transaction is pending, a partial refund will reduce the amount of the transaction.
- If a transaction is posted, a partial refund will create a negative transaction for the refund amount.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/expensify-card/Auto-Reconciliation.md b/docs/articles/expensify-classic/expensify-card/Auto-Reconciliation.md
index b39119ffa4df..73b6c9106e4e 100644
--- a/docs/articles/expensify-classic/expensify-card/Auto-Reconciliation.md
+++ b/docs/articles/expensify-classic/expensify-card/Auto-Reconciliation.md
@@ -168,7 +168,7 @@ If Auto-Reconciliation is disabled for your company's Expensify Cards, a Domain
2. Each time a monthly settlement occurs, Expensify calculates the total purchase amount since the last settlement and creates a Journal Entry. This entry credits the settlement bank account (GL Account) and debits the Expensify Liability Account in Intacct.
3. As expenses are approved and exported to Intacct, Expensify credits the Liability Account and debits the appropriate expense categories.
-# FAQ
+{% include faq-begin.md %}
## What are the timeframes for auto-reconciliation in Expensify?
We offer either daily or monthly auto-reconciliation:
@@ -209,3 +209,5 @@ To address this, please follow these steps:
2. Go to the General Ledger (GL) account where your daily Expensify Card settlement withdrawals are recorded, and locate entries for the dates identified in Step 1.
3. Adjust each settlement entry so that it now posts to the Clearing Account.
4. Create a Journal Entry or Receive Money Transaction to clear the balance in the Liability Account using the funds currently held in the Clearing Account, which was set up in Step 2.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/expensify-card/Cardholder-Settings-and-Features.md b/docs/articles/expensify-classic/expensify-card/Cardholder-Settings-and-Features.md
index 3cb05cb136f6..f24ed57dc655 100644
--- a/docs/articles/expensify-classic/expensify-card/Cardholder-Settings-and-Features.md
+++ b/docs/articles/expensify-classic/expensify-card/Cardholder-Settings-and-Features.md
@@ -76,9 +76,11 @@ There was suspicious activity
- If the spending looks suspicious, we may complete a manual due diligence check, and our team will do this as quickly as possible - your cards will all be locked while this happens.
- The merchant is located in a restricted country
-# FAQ
+{% include faq-begin.md %}
## Can I use Smart Limits with a free Expensify account?
If you're on the Free plan, you won't have the option to use Smart Limits. Your card limit will simply reset at the end of each calendar month.
## I still haven't received my Expensify Card. What should I do?
For more information on why your card hasn't arrived, you can check out this resource on [Requesting a Card](https://help.expensify.com/articles/expensify-classic/expensify-card/Request-the-Card#what-if-i-havent-received-my-card-after-multiple-weeks).
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/expensify-card/Dispute-A-Transaction.md b/docs/articles/expensify-classic/expensify-card/Dispute-A-Transaction.md
index 12dad0c7084d..caf540152063 100644
--- a/docs/articles/expensify-classic/expensify-card/Dispute-A-Transaction.md
+++ b/docs/articles/expensify-classic/expensify-card/Dispute-A-Transaction.md
@@ -46,7 +46,7 @@ To ensure the dispute process goes smoothly, please:
- If you recognize the merchant but not the charge, and you've transacted with them before, contact the merchant directly, as it may be a non-fraudulent error.
- Include supporting documentation like receipts or cancellation confirmations when submitting your dispute to enhance the likelihood of a favorable resolution.
-# FAQ
+{% include faq-begin.md %}
## **How am I protected from fraud using the Expensify Card?**
Real-time push notifications alert you of every card charge upfront, helping identify potential issues immediately. Expensify also leverages sophisticated algorithms to detect and/or block unusual card activity.
@@ -59,3 +59,4 @@ The dispute process can take a few days to a few months. It depends on the type
## **Can I cancel a dispute?**
Contact Concierge if you've filed a dispute and want to cancel it. You might do this if you recognize a previously reported unauthorized charge or if the merchant has already resolved the issue.
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/expensify-card/Expensify-Card-Perks.md b/docs/articles/expensify-classic/expensify-card/Expensify-Card-Perks.md
deleted file mode 100644
index 868ade604451..000000000000
--- a/docs/articles/expensify-classic/expensify-card/Expensify-Card-Perks.md
+++ /dev/null
@@ -1,193 +0,0 @@
----
-title: Expensify Card Perks
-description: Get the most out of your Expensify Card with exclusive perks!
----
-
-
-# Overview
-The Expensify Visa® Commercial Card is packed with perks, both native to our Card program and through exclusive discounts with partnering solutions. The Expensify Card’s primary perks include:
-- Unbeatable cash back incentive with each USD purchase
-
-Below, we’ll cover all of our exclusive offers in more detail and how to claim discounts with our partners.
-
-# Partner Specific Perks
-
-## Amazon AWS
-Whether you are a two-person startup launching a new company or a venture-backed startup, we all could use a little relief in these difficult times. AWS Activate provides you with access to the resources you need to quickly get started on AWS - including free credits, technical support, and training.
-
-All Expensify customers that have adopted The Expensify Card qualify when they add their Expensify Card for billing with AWS!
-
-**Apply now by going [to this link](https://aws.amazon.com/startups/credits) and using the OrgID: 0qyIA (Case Sensitive)**
-
-The full details on the AWS Activate program can be found in AWS's [terms & conditions](https://aws.amazon.com/activate/terms/) and the [Activate FAQs](https://aws.amazon.com/startups/faq).
-
-## Stripe
-Whether you’re creating a subscription service, an on-demand marketplace, or an e-commerce store, Stripe’s integrated payments platform helps you build and scale your business globally.
-
-**Receive waived Stripe fees, if you’re new to Stripe, for your first $5,000 in processed payments.**
-
-**How to redeem:** Sign up for Stripe using your Expensify Card.
-
-## Lamar Advertising
-Lamar provides out-of-home advertising space for clients on billboards, digital, airport displays, transit, and highway logo signs.
-
-**Receive at minimum a 10% discount on your first campaign.**
-
-**How do redeem:** Contact Expensify’s dedicated account manager, Lisa Kane, and mention you’re an Expensify cardholder.
-
-Email: lkane@lamar.com
-
-## Carta
-Simplify equity management with Carta.
-
-**Receive a 20% first-year discount and waived implementation fees for Carta.**
-
-**How to redeem:** Sign up using your Expensify Card
-
-## Pilot
-Pilot specializes in bookkeeping and tax prep for startups and e-commerce providers. When you work with Pilot, you’re paired with a dedicated finance expert who takes the work off your plate and is on hand to answer your questions.
-
-**20% off the first 6-months of Pilot Core**
-
-**How to redeem:** Sign-up using your Expensify Card.
-
-## Spotlight Reporting
-The integrated cloud reporting and forecasting tool that allows you to create insights for better business decisions. Designed by Accountants, for Accountants
-
-**20% discount off your subscription for the first 6 months, plus one free seat to Spotlight Certification.**
-
-**How to redeem:** Sign up using your Expensify Card.
-
-## Guideline
-Guideline's full-service 401(k) plans make it easier and more affordable to offer your employees the retirement benefits they deserve.
-
-**Receive 3 months free.**
-
-**How to redeem:** Sign up using your Expensify Card.
-
-## Gusto
-Gusto's people platform helps businesses like yours onboard, pay, insure, and support your hardworking team. Payroll, benefits, and more
-
-**3 months free service**
-
-**How to redeem:** Sign-up using your Expensify Card.
-
-## QuickBooks Online
-QuickBooks accounting software helps keep your books accurate and up to date, automatically such as: invoicing, cashflow, expense tracking, and more.
-
-**Receive 30% off QuickBooks Online for the first 12 months.**
-
-**How to redeem:** Sign up using your Expensify Card.
-
-## Highfive
-Highfive improves the ease and quality of intelligent in-room video conferencing.
-
-**Receive 50% off the Highfive Select starter package. 10% off the Highfive Premium Package.**
-
-**How to redeem:** Sign-up with your Expensify Card.
-
-## Zendesk
-**$436 in credits for Zendesk Suite products per month for the first year**
-
-How to redeem:
-1. Reach out to startups@zendesk.com with the following: "Expensify asked me to send an email regarding the Zendesk promotion”. You'll receive a code you use in step 5 below.
-2. Start a Zendesk Trial (can be a suite trial or something different) in USD. If your trial is not in USD, contact Zendesk. If you already have a current trial, the code applies and can be used.
-3. From inside your Zendesk trial, click the Buy Now button.
-4. Select your chosen plan with monthly billing. The $436 monthly credit works for up to 4 licenses of the Suite, but the code can also apply $436 to any alternative monthly plan selection.
-5. Enter the promo code that was provided to you in step 1 after emailing Zendesk.
-6. Complete the checkout process and note that once your free credit runs out after 12 monthly billing periods, you will be charged for your next month with Zendesk.
-
-## Xero
-Accounting Software With Everything You Need To Run Your Business Beautifully. Smart Online Accounting. Bank Connections
-
-**U.S. residents get 50% off Xero for six months.**
-
-Head to [this](https://apps.xero.com/us/app/expensify?xtid=x30expensify&utm_source=expensify&utm_medium=web&utm_campaign=cardoffer) page and sign-up for Xero using your Expensify Card!
-
-## Freshworks
-Boost your startup journey with leading customer and employee engagement solutions from Freshworks including CRM, livechat, support, marketing automation, ITSM and HRMS.
-
-How to receive $4,000 in credits on Freshworks products:
-
-[Click here](https://www.freshworks.com/partners/startup-program/expensify-card/) and fill out the form and enter your details, Freshbooks will recognize your company as an Expensify Card customer automatically.
-
-## Slack
-**Receive 25% off for the first year:** You’ll enjoy premium features like unlimited messaging and apps, Slack Connect channels, group video calls, priority support, and much more. It’s all just a click away.
-
-**How to redeem with your Expensify Card:** [Click here](https://slack.com/promo/partner?remote_promo=ead919f5) to redeem the offer by using your Expensify Card to manage the billing.
-
-## Deel.com
-Deel makes onboarding international team members in 150 different countries painless. Quickly bring on contractors or hire employees in seconds with Deel as your employer of record (EOR). It’s one simple, powerful dashboard that houses everything you need. Finalize contracts, pay employees, and manage all your payroll data in one place seamlessly.
-
-**How to redeem 3 months free, then 30% off the rest of the year with Deel.com:** Click [here](https://www.deel.com/partners/expensify) and sign up using your Expensify Card.
-
-## Snap
-**$1,000 in Snap credits**
-Whether you're looking to increase online sales, drive app installs, or get more leads, Snapchat can connect you with a unique mobile audience primed to take action. For a limited time, spend $1000 in Snapchat's Ads Manager and receive $1000 in ad credit to use towards your next campaign!
-
-**How to redeem with your Expensify Card:** Click on `create ad` or `request a call` by clicking here. Enter your details to set up your account if you don't already have one.Add the Expensify Card as your payment option for your Snap Business account.Credits will be automatically placed in your account once you've reached $1,000 in spend.
-
-## Aircall
-Aircall is the cloud-based phone system of choice for modern brands. Aircall allows sales and support teams to have meaningful and efficient phone conversations, and integrates with the most popular CRMs, Help desks, and business tools. Pricing is dependent on the number of users within the account. Discount could range from $270-$9,000+
-
-**2 Months Free**
-
-**How to redeem with your Expensify Card:**
-1. Click [here])(http://pages.aircall.io/Expensify-RewardsPartnerReferral.html)
-2. Sign up for a demo
-3. Let our team know you're an Expensify customer
-
-## NetSuite
-NetSuite helps companies manage core business processes with a cloud-based ERP and accounting software. Expensify has a direct integration with NetSuite so that expenses are coded to your exact preference and data is always synchronized across the two systems.
-
-**10% OFF for the First Year**
-
-**How to redeem:**
-1. Fill out this [Google form](https://community.expensify.com/home/leaving?allowTrusted=1&target=https%3A%2F%2Fdocs.google.com%2Fforms%2Fd%2Fe%2F1FAIpQLSeiOzLrdO-MgqeEMwEqgdQoh4SJBi42MZME9ycHp4SQjlk3bQ%2Fviewform%3Fusp%3Dsf_link).
-2. An Expensify rep will make an introduction to a NetSuite sales rep to get the process started. This offer is only for prospective NetSuite customers. If you are currently a NetSuite customer, this promotion does not apply.
-3. Once you are set up and pay for your first year with NetSuite, we will send you a payment equal to 10% of your first year contract within three months of paying your first NetSuite invoice.
-
-## PagerDuty
-PagerDuty's Platform for Real-Time Operations integrates machine data & human intelligence to improve visibility & agility across organizations.
-
-**25% OFF**
-
-**How to redeem:**
-1. Sign-up using your Expensify Card
-2. Use the discount code EXPENSIFYPDTEAM for a 25% discount on the Team plan or EXPENSIFYPDBUSINESS for a 25% discount on the Business plan within the Cost Summary section upon checkout.
-
-## Typeform
-Typeform makes collecting and sharing information comfortable and conversational. It's a web-based platform you can use to create anything from surveys to apps, without needing to write a single line of code.
-
-**30% off annual premium and professional plans**
-
-**How to redeem with your Expensify Card:**
-1. Click on the 'Get Typeform` by [clicking here](https://try.typeform.com/expensify/?utm_source=expensify&utm_medium=referral&utm_campaign=expensify_integration&utm_content=directory)
-2. Enter your details and setup your free account
-3. Verify your email by clicking on the link that Typeform sends you
-4. Go through the on boarding flow within Tyepform
-5. Click on the 'Upgrade' button from within your workspace
-6. Select your plan
-7. Enter the coupon 'EXPENSIFY30' on the checkout page
-8. Click on 'Upgrade now' once you've filled out all of your payment details with your Expensify Card
-
-## Intercom
-Intercom builds a suite of messaging-first products for businesses to accelerate growth across the customer lifecycle.
-
-**3-months free service**
-
-**How to redeem:** Sign-up using your Expensify Card.
-
-## Talkspace
-Prescription management and personalized treatment from a network of licensed prescribers trained in mental healthcare. Therapists are licensed, verified and background-checked. Working with a Talkspace therapist will give you an unbiased, trained perspective and provide you with the guidance and tools to help you feel better. When it comes to your mental health, the right therapist makes all the difference.
-
-**$125 OFF Talkspace purchases**
-
-**How to redeem with your Expensify Card:** Use the code at EXPENSIFY at the time of checkout.
-
-## Stripe Atlas
-Stripe Atlas helps removes obstacles typically associated with starting a business so you can build your startup from anywhere in the world.
-
-**Receive $100 off Stripe Atlas and get access to a startup toolkit and special offers on additional Strip Atlas services.**
-
-**How to redeem:** Sign up with your Expensify Card.
diff --git a/docs/articles/expensify-classic/expensify-card/Request-the-Card.md b/docs/articles/expensify-classic/expensify-card/Request-the-Card.md
index ca0e7b4709b2..9940535e1fad 100644
--- a/docs/articles/expensify-classic/expensify-card/Request-the-Card.md
+++ b/docs/articles/expensify-classic/expensify-card/Request-the-Card.md
@@ -38,7 +38,7 @@ If you need to cancel your Expensify Card and cannot access the website or mobil
It's not possible to order a replacement card over the phone, so, if applicable, you would need to handle this step from your Expensify account.
-# FAQ
+{% include faq-begin.md %}
## What if I haven’t received my card after multiple weeks?
@@ -47,3 +47,5 @@ Reach out to support, and we can locate a tracking number for the card. If the c
## I’m self-employed. Can I set up the Expensify Card as an individual?
Yep! As long as you have a business bank account and have registered your company with the IRS, you are eligible to use the Expensify Card as an individual business owner.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/expensify-card/Set-Up-the-Card-for-Your-Company.md b/docs/articles/expensify-classic/expensify-card/Set-Up-the-Card-for-Your-Company.md
index e0ef1f3f00fe..464f2129d800 100644
--- a/docs/articles/expensify-classic/expensify-card/Set-Up-the-Card-for-Your-Company.md
+++ b/docs/articles/expensify-classic/expensify-card/Set-Up-the-Card-for-Your-Company.md
@@ -46,7 +46,7 @@ If you have a validated domain, you can set a limit for multiple members by sett
The Company Cards page will act as a hub to view all employees who have been issued a card and where you can view and edit the individual card limits. You’ll also be able to see anyone who has requested a card but doesn’t have one yet.
-# FAQ
+{% include faq-begin.md %}
## Are there foreign transaction fees?
@@ -65,3 +65,5 @@ The Expensify Card is a free corporate card, and no fees are associated with it.
As long as the verified bank account used to apply for the Expensify Card is a US bank account, your cardholders can be anywhere in the world.
Otherwise, the Expensify Card is not available for customers using non-US banks. With that said, launching international support is a top priority for us. Let us know if you’re interested in contacting support, and we’ll reach out as soon as the Expensify Card is available outside the United States.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/expensify-partner-program/How-to-Join-the-ExpensifyApproved!-Partner-Program.md b/docs/articles/expensify-classic/expensify-partner-program/How-to-Join-the-ExpensifyApproved!-Partner-Program.md
deleted file mode 100644
index e14fadbec915..000000000000
--- a/docs/articles/expensify-classic/expensify-partner-program/How-to-Join-the-ExpensifyApproved!-Partner-Program.md
+++ /dev/null
@@ -1,38 +0,0 @@
----
-title: ExpensifyApproved! Partner Program
-description: How to Join the ExpensifyApproved! Partner Program
----
-
-# Overview
-
-As trusted accountants and financial advisors, you strive to offer your clients the best tools available. Expensify is recognized as a leading, all-in-one expense and corporate card management platform suitable for clients of every size. By becoming an ExpensifyApproved! Partner, you unlock exclusive benefits for both you and your clientele.
-## Key Benefits
-Dedicated Partner Manager: Enjoy personalized assistance with an assigned Partner Manager post-course completion.
-Client Onboarding Support: A dedicated Client Onboarding Manager will aid in smooth transitions.
-Free Expensify Account: Complimentary access to our platform for your convenience.
-Revenue share (US-only): All partners receive 0.5% revenue share on client Expensify Card transactions. Keep this as a bonus or offer it to your clients as cash back.
-Exclusive CPA Card (US-only): Automated expense reconciliation from swipe to journal entry with the CPA Card.
-Special Pricing Offers (US-only): Avail partner-specific discounts for your clients and a revenue share from client Expensify Card transactions.
-Professional Growth (US-only): Earn 3 CPE credits after completing the ExpensifyApproved! University.
-Cobranded Marketing - Collaborate with your Partner Manager to craft custom marketing materials, case studies, and more.
-
-# How to join the ExpensifyApproved! Partner Program
-
-1. Enroll in ExpensifyApproved! University (EA!U)
-Visit university.expensify.com and enroll in the “Getting Started with Expensify” course.
-This course imparts the essentials of Expensify, ensuring you follow the best practices for client setups.
-
-2. Complete the course
-Grasp the core features and functionalities of Expensify.
-Ensure you're equipped to serve your clients using Expensify to its fullest.
-Once completed, you’ll be prompted to schedule a call with your Partner Manager. **This call is required to earn your certification.**
-
-3. Once you successfully complete the course, you'll unlock:
-- A dedicated Partner Manager - assigned to you after you have completed the course!
-- A dedicated Client Setup Specialist
-- Membership to the ExpensifyApproved! Partner Program.
-- A complimentary free Expensify account
-- Access to the exclusive CPA Card (US-only).
-- Partner-specific discounts to extend to your clients.
-- A 0.5% revenue share on client Expensify Card expenses (US-only)
-- 3 CPE credits (US-only).
diff --git a/docs/articles/expensify-classic/expensify-partner-program/Partner-Billing-Guide.md b/docs/articles/expensify-classic/expensify-partner-program/Partner-Billing-Guide.md
index 750a1fc10e77..86dbfe5d0720 100644
--- a/docs/articles/expensify-classic/expensify-partner-program/Partner-Billing-Guide.md
+++ b/docs/articles/expensify-classic/expensify-partner-program/Partner-Billing-Guide.md
@@ -63,7 +63,7 @@ Using client IDs for Optimized Billing in Expensify: A unique identifier feature
- Using client IDs for all Workspaces: It's beneficial to use client IDs for all Workspaces to ensure each one is easily recognizable.
- Benefits of itemized billing receipts: Employing client IDs offers itemized billing by client, with each itemization detailing unique active users.
-# FAQ
+{% include faq-begin.md %}
**Do I automatically get the special billing rate as an ExpensifyApproved! Partner?**
- Yes, when you join the ExpensifyApproved! program, you will automatically get the special billing rate. To join the ExpensifyApproved! Program, you need to enroll in ExpensifyApproved! University.
@@ -85,3 +85,5 @@ Using client IDs for Optimized Billing in Expensify: A unique identifier feature
**Where can I see the Billing Receipts?**
- All billing owners receive an emailed PDF of their monthly billing receipt, but a CSV version can also be downloaded from the platform.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/get-paid-back/Per-Diem-Expenses.md b/docs/articles/expensify-classic/get-paid-back/Per-Diem-Expenses.md
index 1b537839af77..e7a43c1d1d61 100644
--- a/docs/articles/expensify-classic/get-paid-back/Per-Diem-Expenses.md
+++ b/docs/articles/expensify-classic/get-paid-back/Per-Diem-Expenses.md
@@ -29,7 +29,7 @@ You can include meal deductions or overnight lodging costs if your jurisdiction
### Step 6: Submit for Approval
Finally, submit your Per Diem expense for approval, and you'll be on your way to getting reimbursed!
-# FAQ
+{% include faq-begin.md %}
## Can I edit my per diem expenses?
Per Diems cannot be amended. To make changes, delete the expense and recreate it as needed.
@@ -43,3 +43,5 @@ Reach out to your internal Admin team, as they've configured the rates in your p
## Can I add start and end times to per diems?
Unfortunately, you cannot add start and end times to Per Diems in Expensify.
By following these steps, you can efficiently create and manage your Per Diem expenses in Expensify, making the process of tracking and getting reimbursed hassle-free.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/get-paid-back/Referral-Program.md b/docs/articles/expensify-classic/get-paid-back/Referral-Program.md
index b4a2b4a7de74..24605dd17d3f 100644
--- a/docs/articles/expensify-classic/get-paid-back/Referral-Program.md
+++ b/docs/articles/expensify-classic/get-paid-back/Referral-Program.md
@@ -1,54 +1,49 @@
---
-title: Expensify Referral Program
-description: Send your joining link, submit a receipt or invoice, and we'll pay you if your referral adopts Expensify.
+title: Earn money with Expensify referrals
+description: Get paid with the Expensify referral program! Share your link, earn $250 per successful sign-up, and enjoy unlimited income potential. It’s that easy.
redirect_from: articles/other/Referral-Program/
---
-# About
+# Earn money with Expensify referrals
-Expensify has grown thanks to our users who love Expensify so much that they tell their friends, colleagues, managers, and fellow business founders to use it, too.
+Picture this: You've found Expensify and it's transformed your approach to expense management and financial organization. You love it so much that you can't help but recommend it to friends, family, and colleagues. Wouldn’t it be nice if you could get rewarded just for spreading the word?
-As a thank you, every time you bring a new user into the platform who directly or indirectly leads to the adoption of a paid annual plan on Expensify, you will earn $250.
+With Expensify referrals, you can. Every time someone you invite to the platform signs up for a paid annual plan on Expensify, you’ll earn $250. Think of it as a thank-you gift from us to you!
-# How to get paid for referring people to Expensify
+## How to get paid for Expensify referrals
-1. Submit a report or invoice, or share your referral link with anyone you know who is spending too much time on expenses, or works at a company that could benefit from using Expensify.
+Here are a few easy ways to get paid for Expensify friend referrals:
-2. You will get $250 for any referred business that commits to an annual subscription, has 2 or more active users, and makes two monthly payments.
+- Submit an expense report to your boss (even just one receipt!)
+- Send an invoice to a client or customer
+- Share your referral link with a friend
+ - To find your referral link, open your Expensify mobile app and go to **Settings > Refer a friend, earn cash! > Share invite link**.
-That’s right! You can refer anyone working at any company you know.
+**If the person you referred commits to an annual subscription with two or more active users and makes two monthly payments, you’ll get $250. Cha-ching!**
-If their company goes on to become an Expensify customer with an annual subscription, and you are the earliest recorded referrer of a user on that company’s paid Expensify Policy, you'll get paid a referral reward.
+## Who can you refer?
-The best way to start is to submit any receipt to your manager (you'll get paid back and set yourself up for $250 if they start a subscription: win-win!)
+You can refer anyone who might benefit from Expensify. Seriously. Anybody.
-Referral rewards for the Spring/Summer 2023 campaign will be paid by direct deposit.
+Know a small business owner? Refer them! An [accountant](https://use.expensify.com/accountants-program)? Refer them! A best friend from childhood who keeps losing paper receipts? Refer them!
-# FAQ
+Plus, you can [refer an unlimited amount of new users](https://use.expensify.com/blog/earn-50000-by-referring-your-friends-to-expensify/) with the Expensify referral program, so your earning potential is truly sky-high.
-- **How will I know if I am the first person to refer a company to Expensify?**
+## Common questions about Expensify benefits
-Successful referrers are notified after their referral pays for 2 months of an annual subscription. We will check for the earliest recorded referrer of a user on the policy, and if that is you, then we will let you know.
+Still have questions about the Expensify referral program? We’ve got answers. Check out our FAQ below.
-- **How will you pay me if I am successful?**
+### How will I know if I am the first person to refer someone to Expensify?
-In the Spring 2023 campaign, Expensify will be paying successful referrers via direct deposit to the Deposit-Only account you have on file. Referral payouts will happen once a month for the duration of the campaign. If you do not have a Deposit-Only account at the time of your referral payout, your deposit will be processed in the next batch.
+You’ll know if you’re the first person to refer someone to Expensify if we reach out to let you know that they’ve successfully adopted Expensify and have paid for two months of an annual subscription.
-Learn how to add a Deposit-Only account [here](https://community.expensify.com/discussion/4641/how-to-add-a-deposit-only-bank-account-both-personal-and-business).
+Simply put, we check for the earliest recorded referrer of a member on the workspace, and if that’s you, then we’ll let you know.
-- **I’m outside of the US, how do I get paid?**
+### My referral wasn’t counted! How can I appeal?
-While our referral payouts are in USD, you will be able to get paid via a Wise Borderless account. Learn more [here](https://community.expensify.com/discussion/5940/how-to-get-reimbursed-outside-the-us-with-wise-for-non-us-employees).
+If you think your Expensify friend referral wasn’t counted, please send a message to concierge@expensify.com with the email of the person you referred. Our team will review the referral and get back to you.
-- **My referral wasn’t counted! How can I appeal?**
+## Share the Expensify love — and get paid in the process
-Expensify reserves the right to modify the terms of the referral program at any time, and pays out referral bonuses for eligible companies at its own discretion.
-
-Please send a message to concierge@expensify.com with the billing owner of the company you have referred and our team will review the referral and get back to you.
-
-- **Where can I find my referral link?**
-
-Expensify members who are opted-in for our newsletters will have received an email containing their unique referral link.
-
-On the mobile app, go to **Settings** > **Invite a Friend** > **Share Invite Link** to retrieve your referral link.
+Who needs a side hustle when you have Expensify? With Expensify benefits, it’s not just about managing your expenses — it's about expanding your income too. Share your Expensify referral link now or send over an invoice to unlock unlimited earning potential.
diff --git a/docs/articles/expensify-classic/get-paid-back/Trips.md b/docs/articles/expensify-classic/get-paid-back/Trips.md
index a65a8bfb8eec..ccfbe1592291 100644
--- a/docs/articles/expensify-classic/get-paid-back/Trips.md
+++ b/docs/articles/expensify-classic/get-paid-back/Trips.md
@@ -28,10 +28,12 @@ To view details about your past or upcoming trips, follow these steps within the
2. Navigate to the "Menu" option (top left ≡ icon)
3. Select **Trips**
-# FAQ
+{% include faq-begin.md %}
## How do I capture Trip receipts sent to my personal email address?
If you received your receipt in an email that is not associated with your Expensify account, you can add this email as a [secondary login](https://help.expensify.com/articles/expensify-classic/account-settings/Account-Details#how-to-add-a-secondary-login) to directly forward the receipt into your account.
## How do I upload Trip receipts that were not sent to me by email?
If your trip receipt was not sent to you by email, you can manually upload the receipt to your account. Check out this resource for more information on [manually uploading receipts](https://help.expensify.com/articles/expensify-classic/get-paid-back/expenses/Upload-Receipts#manually-upload).
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/get-paid-back/expenses/Apply-Tax.md b/docs/articles/expensify-classic/get-paid-back/expenses/Apply-Tax.md
index b5f5ec8be048..c89176bcc0e8 100644
--- a/docs/articles/expensify-classic/get-paid-back/expenses/Apply-Tax.md
+++ b/docs/articles/expensify-classic/get-paid-back/expenses/Apply-Tax.md
@@ -19,7 +19,7 @@ There may be multiple tax rates set up within your Workspace, so if the tax on y
If the tax amount on your receipt is different to the calculated amount or the tax rate doesn’t show up, you can always manually type in the correct tax amount.
-# FAQ
+{% include faq-begin.md %}
## How do I set up multiple taxes (GST/PST/QST) on indirect connections?
Expenses sometimes have more than one tax applied to them - for example in Canada, expenses can have both a Federal GST and a provincial PST or QST.
@@ -37,3 +37,4 @@ Many tax authorities do not require the reporting of tax amounts by rate and the
Alternatively, you can apply each specific tax rate by splitting the expense into the components that each rate will be applied to. To do this, click on **Split Expense** and apply the correct tax rate to each part.
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/get-paid-back/expenses/Merge-Expenses.md b/docs/articles/expensify-classic/get-paid-back/expenses/Merge-Expenses.md
index a8444b98c951..a26146536e42 100644
--- a/docs/articles/expensify-classic/get-paid-back/expenses/Merge-Expenses.md
+++ b/docs/articles/expensify-classic/get-paid-back/expenses/Merge-Expenses.md
@@ -37,7 +37,7 @@ On the mobile app, merging is prompted when you see the message _"Potential dupl
If the expenses exist on two different reports, you will be asked which report you'd like the newly created single expense to be reported onto.
-# FAQ
+{% include faq-begin.md %}
## Can you merge expenses across different reports?
diff --git a/docs/articles/expensify-classic/get-paid-back/expenses/Upload-Receipts.md b/docs/articles/expensify-classic/get-paid-back/expenses/Upload-Receipts.md
index 29380dab5a5b..b0e3ee1b9ade 100644
--- a/docs/articles/expensify-classic/get-paid-back/expenses/Upload-Receipts.md
+++ b/docs/articles/expensify-classic/get-paid-back/expenses/Upload-Receipts.md
@@ -19,7 +19,7 @@ To SmartScan a receipt on your mobile app, tap the green camera button, point an
## Manually Upload
To upload receipts on the web, simply navigate to the Expenses page and click on **New Expense**. Select **Scan Receipt** and choose the file you would like to upload, or drag-and-drop your image directly into the Expenses page, and that will start the SmartScanning process!
-# FAQ
+{% include faq-begin.md %}
## How do you SmartScan multiple receipts?
You can utilize the Rapid Fire Mode to quickly SmartScan multiple receipts at once!
@@ -34,3 +34,5 @@ Once that email address has been added as a Secondary Login, simply forward your
You can crop and rotate a receipt image on the web app, and you can only edit one expense at a time.
Navigate to your Expenses page and locate the expense whose receipt image you'd like to edit, then click the expense to open the Edit screen. If there is an image file associated with the receipt, you will see the Rotate and Crop buttons. Alternatively, you can also navigate to your Reports page, click on a report, and locate the individual expense.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/get-paid-back/reports/Create-A-Report.md b/docs/articles/expensify-classic/get-paid-back/reports/Create-A-Report.md
index ea808695e7cd..88ec2b730d1e 100644
--- a/docs/articles/expensify-classic/get-paid-back/reports/Create-A-Report.md
+++ b/docs/articles/expensify-classic/get-paid-back/reports/Create-A-Report.md
@@ -147,7 +147,7 @@ As you go through each violation, click View to look at the expense in more deta
Click Next to move on to the next item.
Click Finish to complete the review process when you’re done.
-# FAQ
+{% include faq-begin.md %}
## Is there a difference between Expense Reports, Bills, and Invoices?
@@ -164,3 +164,5 @@ If someone external to the business sends you an invoice for their services, you
## When should I submit my report?
Your Company Admin can answer this one, and they may have configured the workspace’s [Scheduled Submit] setting to enforce a regular cadence for you. If not, you can still set this up under your [Individual workspace].
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/getting-started/Invite-Members.md b/docs/articles/expensify-classic/getting-started/Invite-Members.md
index 5b3c17c2e8fb..5a27f58cf2e8 100644
--- a/docs/articles/expensify-classic/getting-started/Invite-Members.md
+++ b/docs/articles/expensify-classic/getting-started/Invite-Members.md
@@ -51,7 +51,7 @@ Here's how it works: If a colleague signs up with a work email address that matc
To enable this feature, go to **Settings > Workspace > Group > *Workspace Name* > People**.
-# FAQ
+{% include faq-begin.md %}
## Who can invite members to Expensify
Any Workspace Admin can add members to a Group Workspace using any of the above methods.
@@ -60,3 +60,5 @@ Under **Settings > Workspace > Group > *Workspace Name* > People > Invite** you
## How can I invite members via the API?
If you would like to integrate an open API HR software, you can use our [Advanced Employee Updater API](https://integrations.expensify.com/Integration-Server/doc/employeeUpdater/) to invite members to your Workspace.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/getting-started/Plan-Types.md b/docs/articles/expensify-classic/getting-started/Plan-Types.md
index 90c632ffa5cc..4f8c52c2e1a1 100644
--- a/docs/articles/expensify-classic/getting-started/Plan-Types.md
+++ b/docs/articles/expensify-classic/getting-started/Plan-Types.md
@@ -20,7 +20,7 @@ The Track plan is tailored for solo Expensify users who don't require expense su
## Individual Submit Plan
The Submit plan is designed for individuals who need to keep track of their expenses and share them with someone else, such as their boss, accountant, or even a housemate. It's specifically tailored for single users who want to both track and submit their expenses efficiently.
-# FAQ
+{% include faq-begin.md %}
## How can I change Individual plans?
You have the flexibility to switch between a Track and Submit plan, or vice versa, at any time by navigating to **Settings > Workspaces > Individual > *Workspace Name* > Plan**. This allows you to adapt your expense management approach as needed.
@@ -30,3 +30,5 @@ You can easily upgrade from a Collect to a Control plan at any time by going to
## How does pricing work if I have two types of Group Workspace plans?
If you have a Control and Collect Workspace, you will be charged at the Control Workspace rate.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/getting-started/Tips-And-Tricks.md b/docs/articles/expensify-classic/getting-started/Tips-and-Tricks.md
similarity index 100%
rename from docs/articles/expensify-classic/getting-started/Tips-And-Tricks.md
rename to docs/articles/expensify-classic/getting-started/Tips-and-Tricks.md
diff --git a/docs/articles/expensify-classic/getting-started/approved-accountants/Card-Revenue-Share-For-Expensify-Approved-Partners.md b/docs/articles/expensify-classic/getting-started/approved-accountants/Card-Revenue-Share-For-Expensify-Approved-Partners.md
index a8e1b0690b72..189ff671b213 100644
--- a/docs/articles/expensify-classic/getting-started/approved-accountants/Card-Revenue-Share-For-Expensify-Approved-Partners.md
+++ b/docs/articles/expensify-classic/getting-started/approved-accountants/Card-Revenue-Share-For-Expensify-Approved-Partners.md
@@ -10,7 +10,7 @@ Start making more with us! We're thrilled to announce a new incentive for our US
# How-to
To benefit from this program, all you need to do is ensure that you are listed as a domain admin on your client's Expensify account. If you're not currently a domain admin, your client can follow the instructions outlined in [our help article](https://community.expensify.com/discussion/5749/how-to-add-and-remove-domain-admins#:~:text=Domain%20Admins%20have%20total%20control,a%20member%20of%20the%20domain.) to assign you this role.
-# FAQ
+{% include faq-begin.md %}
- What if my firm is not permitted to accept revenue share from our clients?
We understand that different firms may have different policies. If your firm is unable to accept this revenue share, you can pass the revenue share back to your client to give them an additional 0.5% of cash back using your own internal payment tools.
- What if my firm does not wish to participate in the program?
diff --git a/docs/articles/expensify-classic/getting-started/approved-accountants/Your-Expensify-Partner-Manager.md b/docs/articles/expensify-classic/getting-started/approved-accountants/Your-Expensify-Partner-Manager.md
index 104cd49daf96..fb3cb5341f61 100644
--- a/docs/articles/expensify-classic/getting-started/approved-accountants/Your-Expensify-Partner-Manager.md
+++ b/docs/articles/expensify-classic/getting-started/approved-accountants/Your-Expensify-Partner-Manager.md
@@ -22,7 +22,7 @@ You can contact your Partner Manager by:
- Signing in to new.expensify.com and searching for your Partner Manager
- Replying to or clicking the chat link on any email you get from your Partner Manager
-# FAQs
+{% include faq-begin.md %}
## How do I know if my Partner Manager is online?
You will be able to see if they are online via their status in new.expensify.com, which will either say “online” or have their working hours.
@@ -32,4 +32,6 @@ If you’re unable to contact your Partner Manager (i.e., they're out of office
## Can I get on a call with my Partner Manager?
Of course! You can ask your Partner Manager to schedule a call whenever you think one might be helpful. Partner Managers can discuss client onboarding strategies, firm wide training, and client setups.
-We recommend continuing to work with Concierge for **general support questions**, as this team is always online and available to help immediately.
\ No newline at end of file
+We recommend continuing to work with Concierge for **general support questions**, as this team is always online and available to help immediately.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/getting-started/support/Expensify-Support.md b/docs/articles/expensify-classic/getting-started/support/Expensify-Support.md
index f4a6acdd8571..870edf959b32 100644
--- a/docs/articles/expensify-classic/getting-started/support/Expensify-Support.md
+++ b/docs/articles/expensify-classic/getting-started/support/Expensify-Support.md
@@ -91,7 +91,7 @@ Your Partner Manager should reach out to you once you've completed ExpensifyAppr
- **Be Clear and Specific**: When asking questions or reporting issues, provide specific examples like affected users' email addresses or report IDs. This makes it easier for us to assist you effectively.
- **Practice Kindness**: Remember that we're here to help. Please be polite, considerate, and patient as we work together to resolve any concerns you have.
-# FAQ
+{% include faq-begin.md %}
## Who gets an Account Manager?
Members who have 10 or more active users, or clients of ExpensifyApproved! Accounts are automatically assigned a dedicated Account Manager.
@@ -115,3 +115,5 @@ We recommend working with Concierge on general support questions, as this team i
## Who gets assigned a Setup Specialist?
This feature is specifically for new members! Whenever you start a free trial, a product Setup Specialist will be assigned to guide you through configuring your Expensify account.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/insights-and-custom-reporting/Default-Export-Templates.md b/docs/articles/expensify-classic/insights-and-custom-reporting/Default-Export-Templates.md
index f6043aaea2eb..b89dca85df04 100644
--- a/docs/articles/expensify-classic/insights-and-custom-reporting/Default-Export-Templates.md
+++ b/docs/articles/expensify-classic/insights-and-custom-reporting/Default-Export-Templates.md
@@ -20,7 +20,7 @@ Below is a breakdown of the available default templates.
3. Click the **Export to** in the top right corner
4. Select the export template you’d like to use
-# FAQ
+{% include faq-begin.md %}
## Why are my numbers exporting in a weird format?
Do your numbers look something like this: 1.7976931348623157e+308? This means that your spreadsheet program is formatting long numbers in an exponential or scientific format. If that happens, you can correct it by changing the data to Plain Text or a Number in your spreadsheet program.
## Why are my leading zeros missing?
@@ -28,3 +28,4 @@ Is the export showing “1” instead of “01”? This means that your spreadsh
## I want a report that is not in the default list, how can I build that?
For a guide on building your own custom template check out Exports > Custom Exports in the Help pages!
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/insights-and-custom-reporting/Insights.md b/docs/articles/expensify-classic/insights-and-custom-reporting/Insights.md
index 6c71630015c5..ce07f4b56450 100644
--- a/docs/articles/expensify-classic/insights-and-custom-reporting/Insights.md
+++ b/docs/articles/expensify-classic/insights-and-custom-reporting/Insights.md
@@ -35,7 +35,7 @@ The Insights dashboard allows you to monitor all aspects of company spend across
2. Build up a report using these [formulas](https://community.expensify.com/discussion/5795/deep-dive-expense-level-formula/p1?new=1)
3. If you need any help, click the **Support** button on the top left to contact your Account Manager
-# FAQs
+{% include faq-begin.md %}
#### Can I share my custom export report?
@@ -98,4 +98,6 @@ We’ve built a huge variety of custom reports for customers, so make sure to re
- Unposted Travel Aging Report
- Vendor Spend
- … or anything you can imagine!
-{% endraw %}
\ No newline at end of file
+{% endraw %}
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/insights-and-custom-reporting/Other-Export-Options.md b/docs/articles/expensify-classic/insights-and-custom-reporting/Other-Export-Options.md
index 7ba84cef6b94..9d752dec3eb9 100644
--- a/docs/articles/expensify-classic/insights-and-custom-reporting/Other-Export-Options.md
+++ b/docs/articles/expensify-classic/insights-and-custom-reporting/Other-Export-Options.md
@@ -30,10 +30,12 @@ The PDF will include all expenses, any attached receipts, and all report notes.
3. Click on **Details** in the top right of the report
4. Click the **print icon**
-# FAQ
+{% include faq-begin.md %}
## Why isn’t my report exporting?
Big reports with lots of expenses may cause the PDF download to fail due to images with large resolutions. In that case, try breaking the report into multiple smaller reports. Also, please note that a report must have at least one expense to be exported or saved as a PDF.
## Can I download multiple PDFs at once?
No, you can’t download multiple reports as PDFs at the same time. If you’d like to export multiple reports, an alternative to consider is the CSV export option.
## The data exported to Excel is showing incorrectly. How can I fix this?
When opening a CSV file export from Expensify in Excel, it’ll automatically register report IDs and transaction IDs as numbers and assign the number format to the report ID column. If a number is greater than a certain length, Excel will contract the number and display it in exponential form. To prevent this, the number needs to be imported as text, which can be done by opening Excel and clicking File > Import > select your CSV file > follow the prompts and on step 3 set the report ID/transactionID column to import as Text.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/integrations/HR-integrations/ADP.md b/docs/articles/expensify-classic/integrations/HR-integrations/ADP.md
index 65b276796c2a..47cbd2fdc1f3 100644
--- a/docs/articles/expensify-classic/integrations/HR-integrations/ADP.md
+++ b/docs/articles/expensify-classic/integrations/HR-integrations/ADP.md
@@ -70,7 +70,7 @@ You can set Custom Fields and Payroll Codes in bulk using a CSV upload in Expens
If you have additional requirements for your ADP upload, for example, additional headings or datasets, reach out to your Expensify Account Manager who will assist you in customizing your ADP export. Expensify Account Managers are trained to accommodate your data requests and help you retrieve them from the system.
-# FAQ
+{% include faq-begin.md %}
- Do I need to convert my employee list into new column headings so I can upload it to Expensify?
@@ -79,3 +79,5 @@ Yes, you’ll need to convert your ADP employee data to the same headings as the
- Can I add special fields/items to my ADP Payroll Custom Export Format?
Yes! You can ask your Expensify Account Manager to help you prepare your ADP Payroll export so that it meets your specific requirements. Just reach out to them via the Chat option in Expensify and they’ll help you get set up.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/integrations/HR-integrations/Gusto.md b/docs/articles/expensify-classic/integrations/HR-integrations/Gusto.md
index f7a5127c9c0e..33a174325bf7 100644
--- a/docs/articles/expensify-classic/integrations/HR-integrations/Gusto.md
+++ b/docs/articles/expensify-classic/integrations/HR-integrations/Gusto.md
@@ -34,7 +34,7 @@ Expensify's direct integration with Gusto will automatically:
2. Click **Save** in the bottom right corner to sync employees into Expensify
3. If the connection is successful, you'll see a summary of how many employees were synced. If any employees were skipped, we'll tell you why.
-# FAQ
+{% include faq-begin.md %}
## Can I import different sets of employees into different Expensify workspaces?
No - Gusto will add all employees to one Expensify workspace, so if you have more than one workspace, you'll need to choose when connecting.
@@ -53,3 +53,5 @@ If your employees are set up in Expensify with their company emails, but with th
To resolve this, you can ask each affected employee to merge their existing Expensify account with the new Expensify account by navigating to **Settings > Account > Account Details** and scrolling down to **Merge Accounts**.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/Certinia.md b/docs/articles/expensify-classic/integrations/accounting-integrations/Certinia.md
index 0856e2694340..6c7014827ea6 100644
--- a/docs/articles/expensify-classic/integrations/accounting-integrations/Certinia.md
+++ b/docs/articles/expensify-classic/integrations/accounting-integrations/Certinia.md
@@ -87,7 +87,7 @@ When exporting to Certinia PSA/SRP you may see up to three different currencies
* Amount field on the Expense line: this currency is derived from the Expensify workspace default report currency.
* Reimbursable Amount on the Expense line: this currency is derived from the currency of the resource with an email matching the report submitter.
-# FAQ
+{% include faq-begin.md %}
## What happens if the report can’t be exported to Certinia?
* The preferred exporter will receive an email outlining the issue and any specific error messages
* Any error messages preventing the export from taking place will be recorded in the report’s history
@@ -148,3 +148,5 @@ Log into Certinia and go to Setup > Manage Users > Users and find the user whose
* Enable Modify All Data and save
Sync the connection within Expensify by going to **Settings** > **Workspaces** > **Groups** > _[Workspace Name]_ > **Connections** > **Sync Now** and then attempt to export the report again
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/Indirect-Accounting-Integrations.md b/docs/articles/expensify-classic/integrations/accounting-integrations/Indirect-Accounting-Integrations.md
index 852db0b7f7c0..09fad1b0ed1a 100644
--- a/docs/articles/expensify-classic/integrations/accounting-integrations/Indirect-Accounting-Integrations.md
+++ b/docs/articles/expensify-classic/integrations/accounting-integrations/Indirect-Accounting-Integrations.md
@@ -30,7 +30,7 @@ To export a report, click **Export To** in the top-left of a report and select y
To export multiple reports, tick the checkbox next to the reports on the **Reports** page, then click **Export To** and select your accounting package from the dropdown menu.
-# FAQ
+{% include faq-begin.md %}
## Which accounting packages offer this indirect integration with Expensify?
@@ -46,3 +46,5 @@ We support a pre-configured flat-file integration for the following accounting p
If your accounting package isn’t listed, but it still accepts a flat-file import, select **Other** when completing the Accounting Software task on your Home page or head to **Settings** > **Workspaces** > **Group** > _Your desired workspace_ > **Export Formats**. This option allows you to create your own templates to export your expense and report data into a format compatible with your accounting system.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/NetSuite.md b/docs/articles/expensify-classic/integrations/accounting-integrations/NetSuite.md
index 8092ed9c6dd6..3ce0d07cb65d 100644
--- a/docs/articles/expensify-classic/integrations/accounting-integrations/NetSuite.md
+++ b/docs/articles/expensify-classic/integrations/accounting-integrations/NetSuite.md
@@ -558,7 +558,7 @@ Here's how you can send them to us:
Send these two files to your Account Manager or Concierge so we can continue troubleshooting!
-# FAQ
+{% include faq-begin.md %}
## What type of Expensify plan is required for connecting to NetSuite?
@@ -573,3 +573,5 @@ If a report is exported to NetSuite and then marked as paid in NetSuite, the rep
## If I enable Auto Sync, what happens to existing approved and reimbursed reports?
If you previously had Auto Sync disabled but want to allow that feature to be used going forward, you can safely turn on Auto Sync without affecting existing reports. Auto Sync will only take effect for reports created after enabling that feature.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md b/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md
index 958e423273ce..8fe31f3ec4f4 100644
--- a/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md
+++ b/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md
@@ -88,7 +88,7 @@ You can bring in Customers/Projects from QuickBooks into Expensify in two ways:
## Items
Items can be imported from QuickBooks as categories alongside your expense accounts.
-# FAQ
+{% include faq-begin.md %}
## How do I sync my connection?
1: Ensure that both the Expensify Sync Manager and QuickBooks Desktop are running.
2: On the Expensify website, navigate to **Settings** > **Policies** > **Group** > _[Policy Name]_ > **Connections** > **QuickBooks Desktop**, and click **Sync now**.
@@ -143,3 +143,5 @@ To resolve this error, follow these steps:
Verify that the Sync Manager's status is **Connected**.
3. If the Sync Manager status is already **Connected**, click **Edit** and then *Save* to refresh the connection. Afterwards, try syncing your policy again.
4. If the error persists, double-check that the token you see in the Sync Manager matches the token in your connection settings.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Online.md b/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Online.md
index 4075aaf18016..623e5f1dd997 100644
--- a/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Online.md
+++ b/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Online.md
@@ -302,7 +302,7 @@ Here are the QuickBooks Online fields that can be mapped as a report field withi
- Customers/Projects
- Locations
-# FAQ
+{% include faq-begin.md %}
## What happens if the report can't be exported to QuickBooks Online automatically?
@@ -320,3 +320,5 @@ To ensure reports are reviewed before export, set up your Workspaces with the ap
- If a report has been exported and reimbursed via ACH, it will be automatically marked as paid in QuickBooks Online during the next sync.
- If a report has been exported and marked as paid in QuickBooks Online, it will be automatically marked as reimbursed in Expensify during the next sync.
- Reports that have yet to be exported to QuickBooks Online won't be automatically exported.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/Sage-Intacct.md b/docs/articles/expensify-classic/integrations/accounting-integrations/Sage-Intacct.md
index ac0a90ba6d37..560a65d0d722 100644
--- a/docs/articles/expensify-classic/integrations/accounting-integrations/Sage-Intacct.md
+++ b/docs/articles/expensify-classic/integrations/accounting-integrations/Sage-Intacct.md
@@ -550,7 +550,7 @@ When ACH reimbursement is enabled, the "Sync Reimbursed Reports" feature will ad
Intacct requires that the target account for the Bill Payment be a Cash and Cash Equivalents account type. If you aren't seeing the account you want in that list, please first confirm that the category on the account is Cash and Cash Equivalents.
-# FAQ
+{% include faq-begin.md %}
## What if my report isn't automatically exported to Sage Intacct?
There are a number of factors that can cause automatic export to fail. If this happens, the preferred exporter will receive an email and an Inbox task outlining the issue and any associated error messages.
The same information will be populated in the comments section of the report.
@@ -566,3 +566,5 @@ If your workspace has been connected to Intacct with Auto Sync disabled, you can
If a report has been exported to Intacct and reimbursed via ACH in Expensify, we'll automatically mark it as paid in Intacct during the next sync.
If a report has been exported to Intacct and marked as paid in Intacct, we'll automatically mark it as reimbursed in Expensify during the next sync.
If a report has not been exported to Intacct, it will not be exported to Intacct automatically.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/Xero.md b/docs/articles/expensify-classic/integrations/accounting-integrations/Xero.md
index 98cc6f2bfdf6..9dd479e90cf1 100644
--- a/docs/articles/expensify-classic/integrations/accounting-integrations/Xero.md
+++ b/docs/articles/expensify-classic/integrations/accounting-integrations/Xero.md
@@ -236,7 +236,7 @@ If we can't find a match, we'll create a new customer record in Xero.
And that's it! You've successfully set up and managed your invoice exports to Xero, making your tracking smooth and efficient.
-# FAQ
+{% include faq-begin.md %}
## Will receipt images be exported to Xero?
@@ -258,3 +258,5 @@ It will be automatically marked as reimbursed in Expensify during the next sync.
Reports that haven't been exported to Xero won't be sent automatically.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Additional-Travel-Integrations.md b/docs/articles/expensify-classic/integrations/travel-integrations/Additional-Travel-Integrations.md
index ac37a01b3e6b..7dcc8e5e9c29 100644
--- a/docs/articles/expensify-classic/integrations/travel-integrations/Additional-Travel-Integrations.md
+++ b/docs/articles/expensify-classic/integrations/travel-integrations/Additional-Travel-Integrations.md
@@ -52,7 +52,7 @@ You can automatically import receipts from many travel platforms into Expensify,
- From your account settings, choose whether expenses should be sent to Expensify automatically or manually.
- We recommend sending them automatically, so you can travel without even thinking about your expense reports.
-# FAQ
+{% include faq-begin.md %}
**Q: What if I don’t have the option for Send to Expensify in Trainline?**
@@ -69,3 +69,5 @@ A: Yes, you can set a weekly or monthly cadence for SpotHero expenses to be emai
**Q: Do I need to select a specific profile before booking in Bolt Work and Grab?**
A: Yes, ensure you have selected your work or business profile as the payment method before booking.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Navan.md b/docs/articles/expensify-classic/integrations/travel-integrations/Navan.md
index 237047fa270e..b1bf3c9745ff 100644
--- a/docs/articles/expensify-classic/integrations/travel-integrations/Navan.md
+++ b/docs/articles/expensify-classic/integrations/travel-integrations/Navan.md
@@ -20,7 +20,7 @@ Once you complete these steps, any flights you book through Navan will automatic
If you booked your Navan flight using your Expensify Card, the Navan expense will automatically merge with the card expense. Learn more about the Expensify Card [here](https://use.expensify.com/company-credit-card).
-# FAQ
+{% include faq-begin.md %}
## How do I expense a prepaid hotel booking in Expensify using the Navan integration?
Bookings that weren’t made in Navan directly (such as a prepaid hotel booking) won’t auto-import into Expensify. To import these trips into Expensify, follow these steps:
@@ -45,3 +45,5 @@ Costs depend on your subscription plans with Expensify and Navan. Expensify does
## How do I disconnect the integration?
To disconnect the integration, navigate to the integrations section in Navan, find Expensify, and select the option to disable the integration.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/manage-employees-and-report-approvals/Removing-Members.md b/docs/articles/expensify-classic/manage-employees-and-report-approvals/Removing-Members.md
index 33ffe7172603..65acc3630582 100644
--- a/docs/articles/expensify-classic/manage-employees-and-report-approvals/Removing-Members.md
+++ b/docs/articles/expensify-classic/manage-employees-and-report-approvals/Removing-Members.md
@@ -13,7 +13,7 @@ Removing a member from a workspace disables their ability to use the workspace.
![image of members table in a workspace]({{site.url}}/assets/images/ExpensifyHelp_RemovingMembers.png){:width="100%"}
-# FAQ
+{% include faq-begin.md %}
## Will reports from this member on this workspace still be available?
Yes, as long as the reports have been submitted. You can navigate to the Reports page and enter the member's email in the search field to find them. However, Draft reports will be removed from the workspace, so these will no longer be visible to the Workspace Admin.
@@ -34,3 +34,5 @@ If a member is a **preferred exporter, billing owner, report approver** or has *
## How do I remove a user completely from a company account?
If you have a Control Workspace and have Domain Control enabled, you will need to remove them from the domain to delete members' accounts entirely and deactivate the Expensify Card.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/manage-employees-and-report-approvals/Vacation-Delegate.md b/docs/articles/expensify-classic/manage-employees-and-report-approvals/Vacation-Delegate.md
index 7c21b12a83e1..4727b1c4a38b 100644
--- a/docs/articles/expensify-classic/manage-employees-and-report-approvals/Vacation-Delegate.md
+++ b/docs/articles/expensify-classic/manage-employees-and-report-approvals/Vacation-Delegate.md
@@ -38,7 +38,7 @@ Your delegate's actions will be noted in the history and comments of each report
The system records every action your vacation delegate takes on your behalf in the **Report History and Comments**. So, you can see when they approved an expense report for you.
-# FAQs
+{% include faq-begin.md %}
## Why can't my Vacation Delegate reimburse reports that they approve?
@@ -50,5 +50,4 @@ If they do not have access to the reimbursement account used on your workspace,
Don't worry, your delegate can also pick their own **Vacation Delegate**. This way, expense reports continue to get approved even if multiple people are away.
-
-
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/send-payments/Pay-Bills.md b/docs/articles/expensify-classic/send-payments/Pay-Bills.md
index 8a5c7c5c7f88..81dcf3488462 100644
--- a/docs/articles/expensify-classic/send-payments/Pay-Bills.md
+++ b/docs/articles/expensify-classic/send-payments/Pay-Bills.md
@@ -70,7 +70,17 @@ To mark a Bill as paid outside of Expensify:
**Fees:** None
-# FAQ
+# Deep Dive: How company bills and vendor invoices are processed in Expensify
+
+Here is how a vendor or supplier bill goes from received to paid in Expensify:
+
+1. When a vendor or supplier bill is received in Expensify via, the document is SmartScanned automatically and a Bill is created. The Bill is owned by the primary domain contact, who will see the Bill on the Reports page on their default group policy.
+2. When the Bill is ready for processing, it is submitted and follows the primary domain contact’s approval workflow. Each time the Bill is approved, it is visible in the next approver's Inbox.
+3. The final approver pays the Bill from their Expensify account on the web via one of the methods.
+4. The Bill is coded with the relevant imported GL codes from a connected accounting software. After it has finished going through the approval workflow the Bill can be exported back to the accounting package connected to the policy.
+
+
+{% include faq-begin.md %}
## What is my company's billing intake email?
Your billing intake email is [yourdomain.com]@expensify.cash. Example, if your domain is `company.io` your billing email is `company.io@expensify.cash`.
@@ -100,11 +110,4 @@ Payments are currently only supported for users paying in United States Dollars
A Bill is a payable which represents an amount owed to a payee (usually a vendor or supplier), and is usually created from a vendor invoice. An Invoice is a receivable, and indicates an amount owed to you by someone else.
-# Deep Dive: How company bills and vendor invoices are processed in Expensify
-
-Here is how a vendor or supplier bill goes from received to paid in Expensify:
-
-1. When a vendor or supplier bill is received in Expensify via, the document is SmartScanned automatically and a Bill is created. The Bill is owned by the primary domain contact, who will see the Bill on the Reports page on their default group policy.
-2. When the Bill is ready for processing, it is submitted and follows the primary domain contact’s approval workflow. Each time the Bill is approved, it is visible in the next approver's Inbox.
-3. The final approver pays the Bill from their Expensify account on the web via one of the methods.
-4. The Bill is coded with the relevant imported GL codes from a connected accounting software. After it has finished going through the approval workflow the Bill can be exported back to the accounting package connected to the policy.
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/send-payments/Reimbursing-Reports.md b/docs/articles/expensify-classic/send-payments/Reimbursing-Reports.md
index e55d99d70827..69b39bae2874 100644
--- a/docs/articles/expensify-classic/send-payments/Reimbursing-Reports.md
+++ b/docs/articles/expensify-classic/send-payments/Reimbursing-Reports.md
@@ -19,6 +19,8 @@ To reimburse directly in Expensify, the following needs to be already configured
If all of those settings are in place, to reimburse a report, you will click **Reimburse** on the report and then select **Via Direct Deposit (ACH)**.
+![Reimbursing Reports Dropdown]({{site.url}}/assets/images/Reimbursing Reports Dropdown.png){:width="100%"}
+
## Indirect or Manual Reimbursement
If you don't have the option to utilize direct reimbursement, you can choose to mark a report as reimbursed by clicking the **Reimburse** button at the top of the report and then selecting **I’ll do it manually – just mark as reimbursed**.
@@ -63,7 +65,7 @@ If either limit has been reached, you can expect funds deposited within your ban
Rapid Reimbursement is not available for non-US-based reimbursement. If you are receiving a reimbursement to a non-US-based deposit account, you should expect to see the funds deposited in your bank account within four business days.
-# FAQ
+{% include faq-begin.md %}
## Who can reimburse reports?
Only a workspace admin who has added a verified business bank account to their Expensify account can reimburse employees.
@@ -73,3 +75,7 @@ Only a workspace admin who has added a verified business bank account to their E
Instead of a bulk reimbursement option, you can set up automatic reimbursement. With this configured, reports below a certain threshold (defined by you) will be automatically reimbursed via ACH as soon as they're "final approved."
To set your manual reimbursement threshold, head to **Settings > Workspace > Group > _[Workspace Name]_ > Reimbursement > Manual Reimbursement**.
+
+![Manual Reimbursement]({{site.url}}/assets/images/Reimbursing Manual.png){:width="100%"}
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/send-payments/Third-Party-Payments.md b/docs/articles/expensify-classic/send-payments/Third-Party-Payments.md
index 1a567dbe6fa3..cae289a0526a 100644
--- a/docs/articles/expensify-classic/send-payments/Third-Party-Payments.md
+++ b/docs/articles/expensify-classic/send-payments/Third-Party-Payments.md
@@ -42,7 +42,7 @@ Once you've set up your third party payment option, you can start using it to re
4. **Track Payment Status**: You can track the status of payments and view transaction details within your Expensify account.
-# FAQ’s
+{% include faq-begin.md %}
## Q: Are there any fees associated with using third party payment options in Expensify?
@@ -57,3 +57,5 @@ A: Expensify allows you to link multiple payment providers if needed. You can se
A: The reimbursement limit may depend on the policies and settings configured within your Expensify account and the limits imposed by your chosen payment provider.
With Expensify's third party payment options, you can simplify your expense management and reimbursement processes. By following the steps outlined in this guide, you can set up and use third party payments efficiently.
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/workspace-and-domain-settings/Budgets.md b/docs/articles/expensify-classic/workspace-and-domain-settings/Budgets.md
index 3c5bc0fe2421..30adac589dc0 100644
--- a/docs/articles/expensify-classic/workspace-and-domain-settings/Budgets.md
+++ b/docs/articles/expensify-classic/workspace-and-domain-settings/Budgets.md
@@ -42,7 +42,7 @@ Expensify’s Budgets feature allows you to:
- **Per individual budget**: you can enter an amount if you want to set a budget per person
- **Notification threshold** - this is the % in which you will be notified as the budgets are hit
-# FAQ
+{% include faq-begin.md %}
## Can I import budgets as a CSV?
At this time, you cannot import budgets via CSV since we don’t import categories or tags from direct accounting integrations.
@@ -54,3 +54,4 @@ Notifications are sent twice:
## How will I be notified when a budget is hit?
A message will be sent in the #admins room of the Workspace.
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/workspace-and-domain-settings/Categories.md b/docs/articles/expensify-classic/workspace-and-domain-settings/Categories.md
index 783bd50f17a3..0cd7ba790a9c 100644
--- a/docs/articles/expensify-classic/workspace-and-domain-settings/Categories.md
+++ b/docs/articles/expensify-classic/workspace-and-domain-settings/Categories.md
@@ -143,7 +143,7 @@ Category violations can happen for the following reasons:
If Scheduled Submit is enabled on a workspace, expenses with category violations will not be auto-submitted unless the expense has a comment added.
-# FAQ
+{% include faq-begin.md %}
## The correct category list isn't showing when one of my employees is categorizing their expenses. Why is this happening?
Its possible the employee is defaulted to their personal workspace so the expenses are not pulling the correct categories to choose from. Check to be sure the report is listed under the correct workspace by looking under the details section on top right of report.
@@ -151,3 +151,4 @@ Its possible the employee is defaulted to their personal workspace so the expens
## Will the account numbers from our accounting system (QuickBooks Online, Sage Intacct, etc.) show in the Category list when employees are choosing what chart of accounts category to code their expense to?
The GL account numbers will be visible in the workspace settings when connected to a Control-level workspace for workspace admins to see. We do not provide this information in an employee-facing capacity because most employees do not have access to that information within the accounting integration.
If you wish to have this information available to your employees when they are categorizing their expenses, you can edit the account name in your accounting software to include the GL number — i.e. **Accounts Payable - 12345**
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/workspace-and-domain-settings/Domains-Overview.md b/docs/articles/expensify-classic/workspace-and-domain-settings/Domains-Overview.md
index cf2f0f59a4a0..6cafe3dccfaf 100644
--- a/docs/articles/expensify-classic/workspace-and-domain-settings/Domains-Overview.md
+++ b/docs/articles/expensify-classic/workspace-and-domain-settings/Domains-Overview.md
@@ -131,10 +131,11 @@ To enable SAML SSO in Expensify you will first need to claim and verify your dom
- For disputing digital Expensify Card purchases, two-factor authentication must be enabled.
- It might take up to 2 hours for domain-level enforcement to take effect, and users will be prompted to configure their individual 2FA settings on their next login to Expensify.
-# FAQ
+{% include faq-begin.md %}
## How many domains can I have?
You can manage multiple domains by adding them through **Settings > Domains > New Domain**. However, to verify additional domains, you must be a Workspace Admin on a Control Workspace. Keep in mind that the Collect plan allows verification for just one domain.
## What’s the difference between claiming a domain and verifying a domain?
Claiming a domain is limited to users with matching email domains, and allows Workspace Admins with a company email to manage bills, company cards, and reconciliation. Verifying a domain offers extra features and security.
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/workspace-and-domain-settings/Expenses.md b/docs/articles/expensify-classic/workspace-and-domain-settings/Expenses.md
index 388bb5d5cbc9..ea701dc09d3e 100644
--- a/docs/articles/expensify-classic/workspace-and-domain-settings/Expenses.md
+++ b/docs/articles/expensify-classic/workspace-and-domain-settings/Expenses.md
@@ -106,7 +106,7 @@ If you enable tax but don’t select a tax rate or enter a tax reclaimable amoun
Note: _Expensify won’t automatically track cumulative mileage. If you need to track cumulative mileage per employee, we recommend building a mileage report using our custom export formulas._
-# FAQs
+{% include faq-begin.md %}
## Why do I see eReceipts for expenses greater than $75?
@@ -116,3 +116,4 @@ An eReceipt is generated for Expensify card purchases of any amount in the follo
Expensify does not update mileage rates to match the rate provided by the IRS. An admin of the workspace will need to update the rate or create a new rate in the workspace. This is because Expensify has customers worldwide, not just in the United States, and most companies want to communicate the change with employees and control the timing.
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/workspace-and-domain-settings/Per-Diem.md b/docs/articles/expensify-classic/workspace-and-domain-settings/Per-Diem.md
index fcb1c8018613..87aef233aeb1 100644
--- a/docs/articles/expensify-classic/workspace-and-domain-settings/Per-Diem.md
+++ b/docs/articles/expensify-classic/workspace-and-domain-settings/Per-Diem.md
@@ -86,7 +86,7 @@ When you _Export to CSV_, Expensify also assigns a Rate ID to each existing rate
Note: _This rate ID corresponds to the Destination+Subrate. You cannot overwrite Destinations, but you can overwrite the Subrate within a Destination by using this rate ID. Always use the “Clear Rate” option with a fresh upload when removing large numbers of rates rather than deleting them individually._
-# FAQs
+{% include faq-begin.md %}
## How do I report on my team's Per Diem expenses?
@@ -95,3 +95,4 @@ Great question! We’ve added a Per Diem export for users to export Per Diem exp
## What if I need help setting the exact rate amounts and currencies?
Right now, Expensify can't help determine what these should be. They vary widely based on your country of origin, the state within that jurisdiction, your company workspace, and the time (usually year) you traveled. There's a demonstration spreadsheet [here](https://s3-us-west-1.amazonaws.com/concierge-responses-expensify-com/uploads%2F1596692482998-Germany+-+Per+Diem.csv), but it shouldn't be used for actual claims unless verified by your internal finance team or accountants.
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/workspace-and-domain-settings/Reimbursement.md b/docs/articles/expensify-classic/workspace-and-domain-settings/Reimbursement.md
index a1916465fca8..ed2384d12006 100644
--- a/docs/articles/expensify-classic/workspace-and-domain-settings/Reimbursement.md
+++ b/docs/articles/expensify-classic/workspace-and-domain-settings/Reimbursement.md
@@ -32,7 +32,7 @@ A Workspace admin can enanble indirect reimbursement via **Settings > Workspaces
**Additional features under Reimbursement > Indirect:**
If you reimburse through a seperate system or through payroll, Expensify can collect and export employee bank account details for you. Just reach out to your Account Manager or concierge@expensify.com for us to add the Reimbursement Details Export format to the account.
-# FAQ
+{% include faq-begin.md %}
## How do I export employee bank account details once the Reimbursement Details Export format is added to my account?
@@ -45,3 +45,4 @@ Bank account names can be updated via **Settings > Accounts > Payments** and cli
## What is the benefit of setting a default reimburser?
The main benefit of being defined as the "reimburser" in the Workspace settings is that this user will receive notifications on their Home page alerting them when reports need to be reimbursed.
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/workspace-and-domain-settings/SAML-SSO.md b/docs/articles/expensify-classic/workspace-and-domain-settings/SAML-SSO.md
index 758cb70067e1..e4b27b238e46 100644
--- a/docs/articles/expensify-classic/workspace-and-domain-settings/SAML-SSO.md
+++ b/docs/articles/expensify-classic/workspace-and-domain-settings/SAML-SSO.md
@@ -77,7 +77,7 @@ To enable SSO with Microsoft ADFS follow these steps:
Assuming you’ve also set up Expensify SAML configuration with your metadata, SAML logins on Expensify.com should now work. For reference, ADFS’ default metadata path is: https://yourservicename.yourdomainname.com/FederationMetadata/2007-06/FederationMetadata.xml.
-# FAQ
+{% include faq-begin.md %}
## What should I do if I’m getting an error when trying to set up SSO?
You can double check your configuration data for errors using samltool.com. If you’re still having issues, you can reach out to your Account Manager or contact Concierge for assistance.
@@ -87,3 +87,4 @@ The entityID for Expensify is https://expensify.com. Remember not to copy and pa
## Can you have multiple domains with only one entityID?
Yes. Please send a message to Concierge or your account manager and we will enable the ability to use the same entityID with multiple domains.
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/workspace-and-domain-settings/Tags.md b/docs/articles/expensify-classic/workspace-and-domain-settings/Tags.md
index 2e6bd335ce4c..d802a183c8ba 100644
--- a/docs/articles/expensify-classic/workspace-and-domain-settings/Tags.md
+++ b/docs/articles/expensify-classic/workspace-and-domain-settings/Tags.md
@@ -78,7 +78,7 @@ Alternatively, if you update the tag details in your accounting integration, be
# Deep Dive
## Make tags required
You can require tags for any workspace expenses by enabling People must tag expenses on the Tags page by navigating to Settings > Workspace > Group > [Workspace Name] > Tags.
-# FAQ
+{% include faq-begin.md %}
## What are the different tag options?
If you want your second tag to depend on the first one, use dependent tags. Include GL codes if needed, especially when using accounting integrations.
@@ -91,4 +91,4 @@ Multi-level tagging is only available with the Control type policy.
## I can’t see "Do you want to use multiple level tags" feature on my company's expense workspace. Why is that?
If you are connected to an accounting integration, you will not see this feature. You will need to add those tags in your integration first, then sync the connection.
-
+{% include faq-end.md %}
diff --git a/docs/articles/new-expensify/bank-accounts/Connect-a-Bank-Account.md b/docs/articles/new-expensify/bank-accounts/Connect-a-Bank-Account.md
index de66315f2d79..307641c9c605 100644
--- a/docs/articles/new-expensify/bank-accounts/Connect-a-Bank-Account.md
+++ b/docs/articles/new-expensify/bank-accounts/Connect-a-Bank-Account.md
@@ -114,7 +114,7 @@ If you get a generic error message that indicates, "Something's gone wrong", ple
8. If you have another phone available, try to follow these steps on that device
If the issue persists, please contact your Account Manager or Concierge for further troubleshooting assistance.
-# FAQ
+{% include faq-begin.md %}
## What is a Beneficial Owner?
A Beneficial Owner refers to an **individual** who owns 25% or more of the business. If no individual owns 25% or more of the business, the company does not have a Beneficial Owner.
@@ -140,3 +140,4 @@ It's a good idea to wait till the end of that second business day. If you still
Make sure to reach out to your Account Manager or Concierge once that's all set, and our team will be able to re-trigger those three test transactions!
+{% include faq-end.md %}
diff --git a/docs/articles/new-expensify/billing-and-plan-types/The-Free-Plan.md b/docs/articles/new-expensify/billing-and-plan-types/The-Free-Plan.md
index 3b79072aa393..b036c5b087d2 100644
--- a/docs/articles/new-expensify/billing-and-plan-types/The-Free-Plan.md
+++ b/docs/articles/new-expensify/billing-and-plan-types/The-Free-Plan.md
@@ -60,7 +60,7 @@ Request an edit an expense or remove an expense before you pay, you can let your
- Automatic submission is already set up, so your admin can pay you back immediately once you create an expense.
- Your admin will get a notification when you send them a new expense, but you can also remind them to pay you by making a comment in the Report History section of your Processing report or chatting with them on new.expensify.com.
-# FAQs
+{% include faq-begin.md %}
## Do I need a business bank account to use the Free Plan?
@@ -145,3 +145,5 @@ Depending on how quickly you report it to us, we may be able to help cancel a re
## As an admin, can I edit users’ expenses and delete them from reports?
No. Only users can edit and delete expenses on the Free plan. Admin control of submitted expenses on a workspace is a feature of our paid plans. If you need something changed, let the user know by commenting in the Report History section of the report on www.expensify.com or by chatting with them in new.expensify.com.
+
+{% include faq-end.md %}
diff --git a/docs/articles/new-expensify/chat/Introducing-Expensify-Chat.md b/docs/articles/new-expensify/chat/Introducing-Expensify-Chat.md
index 25ccdefad261..c7ae49e02292 100644
--- a/docs/articles/new-expensify/chat/Introducing-Expensify-Chat.md
+++ b/docs/articles/new-expensify/chat/Introducing-Expensify-Chat.md
@@ -136,7 +136,7 @@ You will receive a whisper from Concierge any time your content has been flagged
*Note: Any message sent in public chat rooms are automatically reviewed by an automated system looking for offensive content and sent to our moderators for final decisions if it is found.*
-# FAQs
+{% include faq-begin.md %}
## What are the #announce and #admins rooms?
@@ -162,3 +162,4 @@ The way your chats display in the left-hand menu is customizable. We offer two d
- #focus mode will display only unread and pinned chats, and will sort them alphabetically. This setting is perfect for when you need to cut distractions and focus on a crucial project.
You can find your display mode by clicking on your Profile > Preferences > Priority Mode.
+{% include faq-end.md %}
diff --git a/docs/articles/new-expensify/payments/Distance-Requests.md b/docs/articles/new-expensify/payments/Distance-Requests.md
index 91b88409be8b..899cb48fd1f5 100644
--- a/docs/articles/new-expensify/payments/Distance-Requests.md
+++ b/docs/articles/new-expensify/payments/Distance-Requests.md
@@ -20,8 +20,9 @@ Expensify allows you to request reimbursement for mileage by creating a distance
-# FAQs
+{% include faq-begin.md %}
## Is there an easy way to reuse recent locations?
Yes! We save your recently used locations and list them out on the page where you select the Start and Finish.
+{% include faq-end.md %}
diff --git a/docs/articles/new-expensify/payments/Referral-Program.md b/docs/articles/new-expensify/payments/Referral-Program.md
index 6ffb923aeb76..a1b1043dff47 100644
--- a/docs/articles/new-expensify/payments/Referral-Program.md
+++ b/docs/articles/new-expensify/payments/Referral-Program.md
@@ -31,7 +31,7 @@ The sky's the limit for this referral program! Your referral can be anyone - a f
For now, referral rewards will be paid via direct deposit into bank accounts that are connected to Expensify.
-# FAQ
+{% include faq-begin.md %}
- **How will I know if I'm the first person to refer a company to Expensify?**
@@ -54,3 +54,4 @@ Expensify reserves the right to modify the terms of the referral program at any
- **Where can I find my referral link?**
In New Expensify, go to **Settings** > **Share code** > **Get $250** to retrieve your invite link.
+{% include faq-end.md %}
diff --git a/docs/articles/new-expensify/payments/Request-Money.md b/docs/articles/new-expensify/payments/Request-Money.md
index 43a72a075de7..9aac4787484c 100644
--- a/docs/articles/new-expensify/payments/Request-Money.md
+++ b/docs/articles/new-expensify/payments/Request-Money.md
@@ -31,6 +31,7 @@ These two features ensure you can live in the moment and settle up afterward.
- Enter a reason for the split
- The split is then shared equally between the attendees
-# FAQs
+{% include faq-begin.md %}
## Can I request money from more than one person at a time?
If you need to request money for more than one person at a time, you’ll want to use the Split Bill feature. The Request Money option is for one-to-one payments between two people.
+{% include faq-end.md %}
diff --git a/docs/articles/new-expensify/workspace-and-domain-settings/Domain-Settings-Overview.md b/docs/articles/new-expensify/workspace-and-domain-settings/Domain-Settings-Overview.md
index cf2f0f59a4a0..40d759479390 100644
--- a/docs/articles/new-expensify/workspace-and-domain-settings/Domain-Settings-Overview.md
+++ b/docs/articles/new-expensify/workspace-and-domain-settings/Domain-Settings-Overview.md
@@ -131,10 +131,12 @@ To enable SAML SSO in Expensify you will first need to claim and verify your dom
- For disputing digital Expensify Card purchases, two-factor authentication must be enabled.
- It might take up to 2 hours for domain-level enforcement to take effect, and users will be prompted to configure their individual 2FA settings on their next login to Expensify.
-# FAQ
+{% include faq-begin.md %}
## How many domains can I have?
You can manage multiple domains by adding them through **Settings > Domains > New Domain**. However, to verify additional domains, you must be a Workspace Admin on a Control Workspace. Keep in mind that the Collect plan allows verification for just one domain.
## What’s the difference between claiming a domain and verifying a domain?
Claiming a domain is limited to users with matching email domains, and allows Workspace Admins with a company email to manage bills, company cards, and reconciliation. Verifying a domain offers extra features and security.
+
+{% include faq-end.md %}
diff --git a/ios/NewExpensify.xcodeproj/project.pbxproj b/ios/NewExpensify.xcodeproj/project.pbxproj
index c239f4da183f..acd08500fc11 100644
--- a/ios/NewExpensify.xcodeproj/project.pbxproj
+++ b/ios/NewExpensify.xcodeproj/project.pbxproj
@@ -370,7 +370,7 @@
isa = PBXNativeTarget;
buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "NewExpensifyTests" */;
buildPhases = (
- 89BAEBD1F6440299C91536C7 /* [CP] Check Pods Manifest.lock */,
+ A3D1E02743106A34295E533A /* [CP] Check Pods Manifest.lock */,
04B99F6AA578E2A877802F05 /* [Expo] Configure project */,
00E356EA1AD99517003FC87E /* Sources */,
00E356EB1AD99517003FC87E /* Frameworks */,
@@ -614,7 +614,7 @@
"${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipMessageCenterResources.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipPreferenceCenterResources.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/GoogleSignIn/GoogleSignIn.bundle",
- "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
+ "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
@@ -624,7 +624,7 @@
"${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}/GoogleSignIn.bundle",
- "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
+ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@@ -688,7 +688,7 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- 89BAEBD1F6440299C91536C7 /* [CP] Check Pods Manifest.lock */ = {
+ A3D1E02743106A34295E533A /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -783,7 +783,7 @@
"${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipMessageCenterResources.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipPreferenceCenterResources.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/GoogleSignIn/GoogleSignIn.bundle",
- "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/AccessibilityResources.bundle",
+ "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
@@ -793,7 +793,7 @@
"${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}/GoogleSignIn.bundle",
- "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AccessibilityResources.bundle",
+ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@@ -946,7 +946,7 @@
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 368M544MTT;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = "$(SRCROOT)/NewExpensify/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -984,7 +984,7 @@
DEVELOPMENT_TEAM = 368M544MTT;
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 368M544MTT;
INFOPLIST_FILE = NewExpensify/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -1573,9 +1573,15 @@
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = "$(inherited)";
OTHER_CPLUSPLUSFLAGS = "$(inherited)";
+ OTHER_LDFLAGS = (
+ "$(inherited)",
+ "-Wl",
+ "-ld_classic",
+ );
PRODUCT_BUNDLE_IDENTIFIER = "";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
+ USE_HERMES = true;
};
name = DebugDevelopment;
};
@@ -1633,10 +1639,16 @@
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_CFLAGS = "$(inherited)";
OTHER_CPLUSPLUSFLAGS = "$(inherited)";
+ OTHER_LDFLAGS = (
+ "$(inherited)",
+ "-Wl",
+ "-ld_classic",
+ );
PRODUCT_BUNDLE_IDENTIFIER = "";
PRODUCT_NAME = "";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
+ USE_HERMES = true;
VALIDATE_PRODUCT = YES;
};
name = ReleaseDevelopment;
@@ -1703,9 +1715,15 @@
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = "$(inherited)";
OTHER_CPLUSPLUSFLAGS = "$(inherited)";
+ OTHER_LDFLAGS = (
+ "$(inherited)",
+ "-Wl",
+ "-ld_classic",
+ );
PRODUCT_BUNDLE_IDENTIFIER = "";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
+ USE_HERMES = true;
};
name = DebugProduction;
};
@@ -1724,7 +1742,7 @@
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 368M544MTT;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = "$(SRCROOT)/NewExpensify/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -1839,9 +1857,15 @@
ONLY_ACTIVE_ARCH = YES;
OTHER_CFLAGS = "$(inherited)";
OTHER_CPLUSPLUSFLAGS = "$(inherited)";
+ OTHER_LDFLAGS = (
+ "$(inherited)",
+ "-Wl",
+ "-ld_classic",
+ );
PRODUCT_BUNDLE_IDENTIFIER = "";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
+ USE_HERMES = true;
};
name = DebugAdHoc;
};
@@ -1860,7 +1884,7 @@
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 368M544MTT;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = "$(SRCROOT)/NewExpensify/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -1967,10 +1991,16 @@
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_CFLAGS = "$(inherited)";
OTHER_CPLUSPLUSFLAGS = "$(inherited)";
+ OTHER_LDFLAGS = (
+ "$(inherited)",
+ "-Wl",
+ "-ld_classic",
+ );
PRODUCT_BUNDLE_IDENTIFIER = "";
PRODUCT_NAME = "";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
+ USE_HERMES = true;
VALIDATE_PRODUCT = YES;
};
name = ReleaseProduction;
@@ -1989,7 +2019,7 @@
DEVELOPMENT_TEAM = 368M544MTT;
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 368M544MTT;
INFOPLIST_FILE = NewExpensify/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -2093,10 +2123,16 @@
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_CFLAGS = "$(inherited)";
OTHER_CPLUSPLUSFLAGS = "$(inherited)";
+ OTHER_LDFLAGS = (
+ "$(inherited)",
+ "-Wl",
+ "-ld_classic",
+ );
PRODUCT_BUNDLE_IDENTIFIER = "";
PRODUCT_NAME = "";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
+ USE_HERMES = true;
VALIDATE_PRODUCT = YES;
};
name = ReleaseAdHoc;
@@ -2115,7 +2151,7 @@
DEVELOPMENT_TEAM = 368M544MTT;
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 368M544MTT;
INFOPLIST_FILE = NewExpensify/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
diff --git a/ios/NewExpensify/AppDelegate.mm b/ios/NewExpensify/AppDelegate.mm
index 7dbdb20c73b5..f5ddba46f5f1 100644
--- a/ios/NewExpensify/AppDelegate.mm
+++ b/ios/NewExpensify/AppDelegate.mm
@@ -67,7 +67,13 @@ - (BOOL)application:(UIApplication *)application
restorationHandler:restorationHandler];
}
-- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
+- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
+{
+ return [self getBundleURL];
+}
+
+- (NSURL *)getBundleURL
+{
#if DEBUG
return
[[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index ac41382486a5..813c136f3c2c 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -19,7 +19,7 @@
CFBundlePackageTypeAPPLCFBundleShortVersionString
- 1.4.21
+ 1.4.25CFBundleSignature????CFBundleURLTypes
@@ -40,7 +40,7 @@
CFBundleVersion
- 1.4.21.4
+ 1.4.25.1ITSAppUsesNonExemptEncryptionLSApplicationQueriesSchemes
@@ -54,24 +54,9 @@
NSAppTransportSecurityNSAllowsArbitraryLoads
+
+ NSAllowsLocalNetworking
- NSExceptionDomains
-
- localhost
-
- NSExceptionAllowsInsecureHTTPLoads
-
- NSIncludesSubdomains
-
-
- www.expensify.com.dev
-
- NSExceptionAllowsInsecureHTTPLoads
-
- NSIncludesSubdomains
-
-
- NSCameraUsageDescriptionYour camera is used to create chat attachments, documents, and facial capture.
diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist
index ab58f3c293bd..dfa278adacc5 100644
--- a/ios/NewExpensifyTests/Info.plist
+++ b/ios/NewExpensifyTests/Info.plist
@@ -15,10 +15,10 @@
CFBundlePackageTypeBNDLCFBundleShortVersionString
- 1.4.21
+ 1.4.25CFBundleSignature????CFBundleVersion
- 1.4.21.4
+ 1.4.25.1
diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist
index 57421ebf9b75..73420efed711 100644
--- a/ios/NotificationServiceExtension/Info.plist
+++ b/ios/NotificationServiceExtension/Info.plist
@@ -2,6 +2,10 @@
+ CFBundleShortVersionString
+ 1.4.25
+ CFBundleVersion
+ 1.4.25.1NSExtensionNSExtensionPointIdentifier
diff --git a/ios/Podfile b/ios/Podfile
index c12596d3191e..aa87c3e295f3 100644
--- a/ios/Podfile
+++ b/ios/Podfile
@@ -16,7 +16,7 @@ node_require('react-native/scripts/react_native_pods.rb')
node_require('react-native-permissions/scripts/setup.rb')
# Our min supported iOS version is higher than the default (min_ios_version_supported) to support libraires such as Airship
-platform :ios, 13
+platform :ios, 13.4
prepare_react_native_project!
setup_permissions([
@@ -84,14 +84,8 @@ target 'NewExpensify' do
config = use_native_modules!
- # Flags change depending on the env values.
- flags = get_default_flags()
-
use_react_native!(
:path => config[:reactNativePath],
- # Hermes is now enabled by default. Disable by setting this flag to false.
- :hermes_enabled => flags[:hermes_enabled],
- :fabric_enabled => flags[:fabric_enabled],
# Enables Flipper.
#
# Note that if you have use_frameworks! enabled, Flipper will not work and
@@ -117,7 +111,6 @@ target 'NewExpensify' do
config[:reactNativePath],
:mac_catalyst_enabled => false
)
- __apply_Xcode_12_5_M1_post_install_workaround(installer)
__apply_Xcode_14_3_RC_post_install_workaround(installer)
installer.pods_project.targets.each do |target|
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 77c390c46416..379194a70fd9 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -27,35 +27,34 @@ PODS:
- AppAuth/Core (1.6.2)
- AppAuth/ExternalUserAgent (1.6.2):
- AppAuth/Core
- - boost (1.76.0)
+ - boost (1.83.0)
- BVLinearGradient (2.8.1):
- React-Core
- CocoaAsyncSocket (7.6.5)
- DoubleConversion (1.1.6)
- - EXApplication (5.3.1):
+ - Expo (50.0.0-preview.7):
- ExpoModulesCore
- - Expo (49.0.21):
- - ExpoModulesCore
- - ExpoImage (1.8.1):
+ - ExpoImage (1.10.1):
- ExpoModulesCore
- SDWebImage (~> 5.17.0)
- SDWebImageAVIFCoder (~> 0.10.1)
- SDWebImageSVGCoder (~> 1.7.0)
- SDWebImageWebPCoder (~> 0.13.0)
- - ExpoModulesCore (1.5.12):
- - RCT-Folly (= 2021.07.22.00)
+ - ExpoModulesCore (1.11.4):
+ - glog
+ - RCT-Folly (= 2022.05.16.00)
- React-Core
- React-NativeModulesApple
- React-RCTAppDelegate
- ReactCommon/turbomodule/core
- - FBLazyVector (0.72.4)
- - FBReactNativeSpec (0.72.4):
- - RCT-Folly (= 2021.07.22.00)
- - RCTRequired (= 0.72.4)
- - RCTTypeSafety (= 0.72.4)
- - React-Core (= 0.72.4)
- - React-jsi (= 0.72.4)
- - ReactCommon/turbomodule/core (= 0.72.4)
+ - FBLazyVector (0.73.2)
+ - FBReactNativeSpec (0.73.2):
+ - RCT-Folly (= 2022.05.16.00)
+ - RCTRequired (= 0.73.2)
+ - RCTTypeSafety (= 0.73.2)
+ - React-Core (= 0.73.2)
+ - React-jsi (= 0.73.2)
+ - ReactCommon/turbomodule/core (= 0.73.2)
- Firebase/Analytics (8.8.0):
- Firebase/Core
- Firebase/Core (8.8.0):
@@ -125,7 +124,7 @@ PODS:
- FirebaseInstallations (~> 8.0)
- GoogleUtilities/Environment (~> 7.7)
- "GoogleUtilities/NSData+zlib (~> 7.7)"
- - Flipper (0.182.0):
+ - Flipper (0.201.0):
- Flipper-Folly (~> 2.6)
- Flipper-Boost-iOSX (1.76.0.1.11)
- Flipper-DoubleConversion (3.2.0.1)
@@ -139,48 +138,46 @@ PODS:
- OpenSSL-Universal (= 1.1.1100)
- Flipper-Glog (0.5.0.5)
- Flipper-PeerTalk (0.0.4)
- - FlipperKit (0.182.0):
- - FlipperKit/Core (= 0.182.0)
- - FlipperKit/Core (0.182.0):
- - Flipper (~> 0.182.0)
+ - FlipperKit (0.201.0):
+ - FlipperKit/Core (= 0.201.0)
+ - FlipperKit/Core (0.201.0):
+ - Flipper (~> 0.201.0)
- FlipperKit/CppBridge
- FlipperKit/FBCxxFollyDynamicConvert
- FlipperKit/FBDefines
- FlipperKit/FKPortForwarding
- SocketRocket (~> 0.6.0)
- - FlipperKit/CppBridge (0.182.0):
- - Flipper (~> 0.182.0)
- - FlipperKit/FBCxxFollyDynamicConvert (0.182.0):
+ - FlipperKit/CppBridge (0.201.0):
+ - Flipper (~> 0.201.0)
+ - FlipperKit/FBCxxFollyDynamicConvert (0.201.0):
- Flipper-Folly (~> 2.6)
- - FlipperKit/FBDefines (0.182.0)
- - FlipperKit/FKPortForwarding (0.182.0):
+ - FlipperKit/FBDefines (0.201.0)
+ - FlipperKit/FKPortForwarding (0.201.0):
- CocoaAsyncSocket (~> 7.6)
- Flipper-PeerTalk (~> 0.0.4)
- - FlipperKit/FlipperKitHighlightOverlay (0.182.0)
- - FlipperKit/FlipperKitLayoutHelpers (0.182.0):
+ - FlipperKit/FlipperKitHighlightOverlay (0.201.0)
+ - FlipperKit/FlipperKitLayoutHelpers (0.201.0):
- FlipperKit/Core
- FlipperKit/FlipperKitHighlightOverlay
- FlipperKit/FlipperKitLayoutTextSearchable
- - FlipperKit/FlipperKitLayoutIOSDescriptors (0.182.0):
+ - FlipperKit/FlipperKitLayoutIOSDescriptors (0.201.0):
- FlipperKit/Core
- FlipperKit/FlipperKitHighlightOverlay
- FlipperKit/FlipperKitLayoutHelpers
- - YogaKit (~> 1.18)
- - FlipperKit/FlipperKitLayoutPlugin (0.182.0):
+ - FlipperKit/FlipperKitLayoutPlugin (0.201.0):
- FlipperKit/Core
- FlipperKit/FlipperKitHighlightOverlay
- FlipperKit/FlipperKitLayoutHelpers
- FlipperKit/FlipperKitLayoutIOSDescriptors
- FlipperKit/FlipperKitLayoutTextSearchable
- - YogaKit (~> 1.18)
- - FlipperKit/FlipperKitLayoutTextSearchable (0.182.0)
- - FlipperKit/FlipperKitNetworkPlugin (0.182.0):
+ - FlipperKit/FlipperKitLayoutTextSearchable (0.201.0)
+ - FlipperKit/FlipperKitNetworkPlugin (0.201.0):
- FlipperKit/Core
- - FlipperKit/FlipperKitReactPlugin (0.182.0):
+ - FlipperKit/FlipperKitReactPlugin (0.201.0):
- FlipperKit/Core
- - FlipperKit/FlipperKitUserDefaultsPlugin (0.182.0):
+ - FlipperKit/FlipperKitUserDefaultsPlugin (0.201.0):
- FlipperKit/Core
- - FlipperKit/SKIOSNetworkPlugin (0.182.0):
+ - FlipperKit/SKIOSNetworkPlugin (0.201.0):
- FlipperKit/Core
- FlipperKit/FlipperKitNetworkPlugin
- fmt (6.2.1)
@@ -205,7 +202,7 @@ PODS:
- GoogleUtilities/Network (~> 7.4)
- "GoogleUtilities/NSData+zlib (~> 7.4)"
- nanopb (~> 2.30908.0)
- - GoogleDataTransport (9.2.3):
+ - GoogleDataTransport (9.3.0):
- GoogleUtilities/Environment (~> 7.7)
- nanopb (< 2.30910.0, >= 2.30908.0)
- PromisesObjC (< 3.0, >= 1.2)
@@ -213,33 +210,33 @@ PODS:
- AppAuth (~> 1.5)
- GTMAppAuth (< 3.0, >= 1.3)
- GTMSessionFetcher/Core (< 4.0, >= 1.1)
- - GoogleUtilities/AppDelegateSwizzler (7.11.1):
+ - GoogleUtilities/AppDelegateSwizzler (7.12.0):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
- GoogleUtilities/Network
- - GoogleUtilities/Environment (7.11.1):
+ - GoogleUtilities/Environment (7.12.0):
- PromisesObjC (< 3.0, >= 1.2)
- - GoogleUtilities/ISASwizzler (7.11.1)
- - GoogleUtilities/Logger (7.11.1):
+ - GoogleUtilities/ISASwizzler (7.12.0)
+ - GoogleUtilities/Logger (7.12.0):
- GoogleUtilities/Environment
- - GoogleUtilities/MethodSwizzler (7.11.1):
+ - GoogleUtilities/MethodSwizzler (7.12.0):
- GoogleUtilities/Logger
- - GoogleUtilities/Network (7.11.1):
+ - GoogleUtilities/Network (7.12.0):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Reachability
- - "GoogleUtilities/NSData+zlib (7.11.1)"
- - GoogleUtilities/Reachability (7.11.1):
+ - "GoogleUtilities/NSData+zlib (7.12.0)"
+ - GoogleUtilities/Reachability (7.12.0):
- GoogleUtilities/Logger
- - GoogleUtilities/UserDefaults (7.11.1):
+ - GoogleUtilities/UserDefaults (7.12.0):
- GoogleUtilities/Logger
- GTMAppAuth (2.0.0):
- AppAuth/Core (~> 1.6)
- GTMSessionFetcher/Core (< 4.0, >= 1.5)
- - GTMSessionFetcher/Core (3.1.1)
- - hermes-engine (0.72.4):
- - hermes-engine/Pre-built (= 0.72.4)
- - hermes-engine/Pre-built (0.72.4)
+ - GTMSessionFetcher/Core (3.2.0)
+ - hermes-engine (0.73.2):
+ - hermes-engine/Pre-built (= 0.73.2)
+ - hermes-engine/Pre-built (0.73.2)
- libaom (3.0.0):
- libvmaf (>= 2.2.0)
- libavif (0.11.1):
@@ -262,8 +259,8 @@ PODS:
- libwebp/sharpyuv (1.3.2)
- libwebp/webp (1.3.2):
- libwebp/sharpyuv
- - lottie-ios (4.3.3)
- - lottie-react-native (6.4.0):
+ - lottie-ios (4.3.4)
+ - lottie-react-native (6.4.1):
- lottie-ios (~> 4.3.3)
- React-Core
- MapboxCommon (23.6.0)
@@ -280,50 +277,55 @@ PODS:
- nanopb/encode (= 2.30908.0)
- nanopb/decode (2.30908.0)
- nanopb/encode (2.30908.0)
- - Onfido (28.3.0)
+ - Onfido (28.3.1)
- onfido-react-native-sdk (8.3.0):
- Onfido (~> 28.3.0)
- React
- OpenSSL-Universal (1.1.1100)
- Plaid (4.7.0)
- - PromisesObjC (2.2.0)
- - RCT-Folly (2021.07.22.00):
+ - PromisesObjC (2.3.1)
+ - RCT-Folly (2022.05.16.00):
+ - boost
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - RCT-Folly/Default (= 2022.05.16.00)
+ - RCT-Folly/Default (2022.05.16.00):
- boost
- DoubleConversion
- fmt (~> 6.2.1)
- glog
- - RCT-Folly/Default (= 2021.07.22.00)
- - RCT-Folly/Default (2021.07.22.00):
+ - RCT-Folly/Fabric (2022.05.16.00):
- boost
- DoubleConversion
- fmt (~> 6.2.1)
- glog
- - RCT-Folly/Futures (2021.07.22.00):
+ - RCT-Folly/Futures (2022.05.16.00):
- boost
- DoubleConversion
- fmt (~> 6.2.1)
- glog
- libevent
- - RCTRequired (0.72.4)
- - RCTTypeSafety (0.72.4):
- - FBLazyVector (= 0.72.4)
- - RCTRequired (= 0.72.4)
- - React-Core (= 0.72.4)
- - React (0.72.4):
- - React-Core (= 0.72.4)
- - React-Core/DevSupport (= 0.72.4)
- - React-Core/RCTWebSocket (= 0.72.4)
- - React-RCTActionSheet (= 0.72.4)
- - React-RCTAnimation (= 0.72.4)
- - React-RCTBlob (= 0.72.4)
- - React-RCTImage (= 0.72.4)
- - React-RCTLinking (= 0.72.4)
- - React-RCTNetwork (= 0.72.4)
- - React-RCTSettings (= 0.72.4)
- - React-RCTText (= 0.72.4)
- - React-RCTVibration (= 0.72.4)
- - React-callinvoker (0.72.4)
- - React-Codegen (0.72.4):
+ - RCTRequired (0.73.2)
+ - RCTTypeSafety (0.73.2):
+ - FBLazyVector (= 0.73.2)
+ - RCTRequired (= 0.73.2)
+ - React-Core (= 0.73.2)
+ - React (0.73.2):
+ - React-Core (= 0.73.2)
+ - React-Core/DevSupport (= 0.73.2)
+ - React-Core/RCTWebSocket (= 0.73.2)
+ - React-RCTActionSheet (= 0.73.2)
+ - React-RCTAnimation (= 0.73.2)
+ - React-RCTBlob (= 0.73.2)
+ - React-RCTImage (= 0.73.2)
+ - React-RCTLinking (= 0.73.2)
+ - React-RCTNetwork (= 0.73.2)
+ - React-RCTSettings (= 0.73.2)
+ - React-RCTText (= 0.73.2)
+ - React-RCTVibration (= 0.73.2)
+ - React-callinvoker (0.73.2)
+ - React-Codegen (0.73.2):
- DoubleConversion
- FBReactNativeSpec
- glog
@@ -338,255 +340,821 @@ PODS:
- React-rncore
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- - React-Core (0.72.4):
+ - React-Core (0.73.2):
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
- - React-Core/Default (= 0.72.4)
+ - RCT-Folly (= 2022.05.16.00)
+ - React-Core/Default (= 0.73.2)
- React-cxxreact
- React-hermes
- React-jsi
- React-jsiexecutor
- React-perflogger
- - React-runtimeexecutor
+ - React-runtimescheduler
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/CoreModulesHeaders (0.72.4):
+ - React-Core/CoreModulesHeaders (0.73.2):
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
+ - RCT-Folly (= 2022.05.16.00)
- React-Core/Default
- React-cxxreact
- React-hermes
- React-jsi
- React-jsiexecutor
- React-perflogger
- - React-runtimeexecutor
+ - React-runtimescheduler
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/Default (0.72.4):
+ - React-Core/Default (0.73.2):
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
+ - RCT-Folly (= 2022.05.16.00)
- React-cxxreact
- React-hermes
- React-jsi
- React-jsiexecutor
- React-perflogger
- - React-runtimeexecutor
+ - React-runtimescheduler
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/DevSupport (0.72.4):
+ - React-Core/DevSupport (0.73.2):
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
- - React-Core/Default (= 0.72.4)
- - React-Core/RCTWebSocket (= 0.72.4)
+ - RCT-Folly (= 2022.05.16.00)
+ - React-Core/Default (= 0.73.2)
+ - React-Core/RCTWebSocket (= 0.73.2)
- React-cxxreact
- React-hermes
- React-jsi
- React-jsiexecutor
- - React-jsinspector (= 0.72.4)
+ - React-jsinspector (= 0.73.2)
- React-perflogger
- - React-runtimeexecutor
+ - React-runtimescheduler
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/RCTActionSheetHeaders (0.72.4):
+ - React-Core/RCTActionSheetHeaders (0.73.2):
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
+ - RCT-Folly (= 2022.05.16.00)
- React-Core/Default
- React-cxxreact
- React-hermes
- React-jsi
- React-jsiexecutor
- React-perflogger
- - React-runtimeexecutor
+ - React-runtimescheduler
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/RCTAnimationHeaders (0.72.4):
+ - React-Core/RCTAnimationHeaders (0.73.2):
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
+ - RCT-Folly (= 2022.05.16.00)
- React-Core/Default
- React-cxxreact
- React-hermes
- React-jsi
- React-jsiexecutor
- React-perflogger
- - React-runtimeexecutor
+ - React-runtimescheduler
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/RCTBlobHeaders (0.72.4):
+ - React-Core/RCTBlobHeaders (0.73.2):
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
+ - RCT-Folly (= 2022.05.16.00)
- React-Core/Default
- React-cxxreact
- React-hermes
- React-jsi
- React-jsiexecutor
- React-perflogger
- - React-runtimeexecutor
+ - React-runtimescheduler
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/RCTImageHeaders (0.72.4):
+ - React-Core/RCTImageHeaders (0.73.2):
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
+ - RCT-Folly (= 2022.05.16.00)
- React-Core/Default
- React-cxxreact
- React-hermes
- React-jsi
- React-jsiexecutor
- React-perflogger
- - React-runtimeexecutor
+ - React-runtimescheduler
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/RCTLinkingHeaders (0.72.4):
+ - React-Core/RCTLinkingHeaders (0.73.2):
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
+ - RCT-Folly (= 2022.05.16.00)
- React-Core/Default
- React-cxxreact
- React-hermes
- React-jsi
- React-jsiexecutor
- React-perflogger
- - React-runtimeexecutor
+ - React-runtimescheduler
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/RCTNetworkHeaders (0.72.4):
+ - React-Core/RCTNetworkHeaders (0.73.2):
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
+ - RCT-Folly (= 2022.05.16.00)
- React-Core/Default
- React-cxxreact
- React-hermes
- React-jsi
- React-jsiexecutor
- React-perflogger
- - React-runtimeexecutor
+ - React-runtimescheduler
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/RCTSettingsHeaders (0.72.4):
+ - React-Core/RCTSettingsHeaders (0.73.2):
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
+ - RCT-Folly (= 2022.05.16.00)
- React-Core/Default
- React-cxxreact
- React-hermes
- React-jsi
- React-jsiexecutor
- React-perflogger
- - React-runtimeexecutor
+ - React-runtimescheduler
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/RCTTextHeaders (0.72.4):
+ - React-Core/RCTTextHeaders (0.73.2):
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
+ - RCT-Folly (= 2022.05.16.00)
- React-Core/Default
- React-cxxreact
- React-hermes
- React-jsi
- React-jsiexecutor
- React-perflogger
- - React-runtimeexecutor
+ - React-runtimescheduler
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/RCTVibrationHeaders (0.72.4):
+ - React-Core/RCTVibrationHeaders (0.73.2):
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
+ - RCT-Folly (= 2022.05.16.00)
- React-Core/Default
- React-cxxreact
- React-hermes
- React-jsi
- React-jsiexecutor
- React-perflogger
- - React-runtimeexecutor
+ - React-runtimescheduler
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/RCTWebSocket (0.72.4):
+ - React-Core/RCTWebSocket (0.73.2):
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
- - React-Core/Default (= 0.72.4)
+ - RCT-Folly (= 2022.05.16.00)
+ - React-Core/Default (= 0.73.2)
- React-cxxreact
- React-hermes
- React-jsi
- React-jsiexecutor
- React-perflogger
- - React-runtimeexecutor
+ - React-runtimescheduler
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-CoreModules (0.72.4):
- - RCT-Folly (= 2021.07.22.00)
- - RCTTypeSafety (= 0.72.4)
- - React-Codegen (= 0.72.4)
- - React-Core/CoreModulesHeaders (= 0.72.4)
- - React-jsi (= 0.72.4)
+ - React-CoreModules (0.73.2):
+ - RCT-Folly (= 2022.05.16.00)
+ - RCTTypeSafety (= 0.73.2)
+ - React-Codegen
+ - React-Core/CoreModulesHeaders (= 0.73.2)
+ - React-jsi (= 0.73.2)
+ - React-NativeModulesApple
- React-RCTBlob
- - React-RCTImage (= 0.72.4)
- - ReactCommon/turbomodule/core (= 0.72.4)
+ - React-RCTImage (= 0.73.2)
+ - ReactCommon
- SocketRocket (= 0.6.1)
- - React-cxxreact (0.72.4):
- - boost (= 1.76.0)
+ - React-cxxreact (0.73.2):
+ - boost (= 1.83.0)
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly (= 2022.05.16.00)
+ - React-callinvoker (= 0.73.2)
+ - React-debug (= 0.73.2)
+ - React-jsi (= 0.73.2)
+ - React-jsinspector (= 0.73.2)
+ - React-logger (= 0.73.2)
+ - React-perflogger (= 0.73.2)
+ - React-runtimeexecutor (= 0.73.2)
+ - React-debug (0.73.2)
+ - React-Fabric (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-Fabric/animations (= 0.73.2)
+ - React-Fabric/attributedstring (= 0.73.2)
+ - React-Fabric/componentregistry (= 0.73.2)
+ - React-Fabric/componentregistrynative (= 0.73.2)
+ - React-Fabric/components (= 0.73.2)
+ - React-Fabric/core (= 0.73.2)
+ - React-Fabric/imagemanager (= 0.73.2)
+ - React-Fabric/leakchecker (= 0.73.2)
+ - React-Fabric/mounting (= 0.73.2)
+ - React-Fabric/scheduler (= 0.73.2)
+ - React-Fabric/telemetry (= 0.73.2)
+ - React-Fabric/templateprocessor (= 0.73.2)
+ - React-Fabric/textlayoutmanager (= 0.73.2)
+ - React-Fabric/uimanager (= 0.73.2)
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/animations (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/attributedstring (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/componentregistry (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/componentregistrynative (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/components (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-Fabric/components/inputaccessory (= 0.73.2)
+ - React-Fabric/components/legacyviewmanagerinterop (= 0.73.2)
+ - React-Fabric/components/modal (= 0.73.2)
+ - React-Fabric/components/rncore (= 0.73.2)
+ - React-Fabric/components/root (= 0.73.2)
+ - React-Fabric/components/safeareaview (= 0.73.2)
+ - React-Fabric/components/scrollview (= 0.73.2)
+ - React-Fabric/components/text (= 0.73.2)
+ - React-Fabric/components/textinput (= 0.73.2)
+ - React-Fabric/components/unimplementedview (= 0.73.2)
+ - React-Fabric/components/view (= 0.73.2)
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/components/inputaccessory (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/components/legacyviewmanagerinterop (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/components/modal (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/components/rncore (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/components/root (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/components/safeareaview (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/components/scrollview (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/components/text (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/components/textinput (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/components/unimplementedview (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/components/view (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - Yoga
+ - React-Fabric/core (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/imagemanager (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/leakchecker (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/mounting (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/scheduler (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/telemetry (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/templateprocessor (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/textlayoutmanager (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-Fabric/uimanager
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-Fabric/uimanager (0.73.2):
- DoubleConversion
+ - fmt (~> 6.2.1)
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
- - React-callinvoker (= 0.72.4)
- - React-debug (= 0.72.4)
- - React-jsi (= 0.72.4)
- - React-jsinspector (= 0.72.4)
- - React-logger (= 0.72.4)
- - React-perflogger (= 0.72.4)
- - React-runtimeexecutor (= 0.72.4)
- - React-debug (0.72.4)
- - React-hermes (0.72.4):
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Core
+ - React-cxxreact
+ - React-debug
+ - React-graphics
+ - React-jsi
+ - React-jsiexecutor
+ - React-logger
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - ReactCommon/turbomodule/core
+ - React-FabricImage (0.73.2):
- DoubleConversion
+ - fmt (~> 6.2.1)
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
- - RCT-Folly/Futures (= 2021.07.22.00)
- - React-cxxreact (= 0.72.4)
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - RCTRequired (= 0.73.2)
+ - RCTTypeSafety (= 0.73.2)
+ - React-Fabric
+ - React-graphics
+ - React-ImageManager
- React-jsi
- - React-jsiexecutor (= 0.72.4)
- - React-jsinspector (= 0.72.4)
- - React-perflogger (= 0.72.4)
- - React-jsi (0.72.4):
- - boost (= 1.76.0)
+ - React-jsiexecutor (= 0.73.2)
+ - React-logger
+ - React-rendererdebug
+ - React-utils
+ - ReactCommon
+ - Yoga
+ - React-graphics (0.73.2):
+ - glog
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - React-Core/Default (= 0.73.2)
+ - React-utils
+ - React-hermes (0.73.2):
- DoubleConversion
+ - fmt (~> 6.2.1)
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
- - React-jsiexecutor (0.72.4):
+ - RCT-Folly (= 2022.05.16.00)
+ - RCT-Folly/Futures (= 2022.05.16.00)
+ - React-cxxreact (= 0.73.2)
+ - React-jsi
+ - React-jsiexecutor (= 0.73.2)
+ - React-jsinspector (= 0.73.2)
+ - React-perflogger (= 0.73.2)
+ - React-ImageManager (0.73.2):
+ - glog
+ - RCT-Folly/Fabric
+ - React-Core/Default
+ - React-debug
+ - React-Fabric
+ - React-graphics
+ - React-rendererdebug
+ - React-utils
+ - React-jserrorhandler (0.73.2):
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - React-debug
+ - React-jsi
+ - React-Mapbuffer
+ - React-jsi (0.73.2):
+ - boost (= 1.83.0)
- DoubleConversion
+ - fmt (~> 6.2.1)
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
- - React-cxxreact (= 0.72.4)
- - React-jsi (= 0.72.4)
- - React-perflogger (= 0.72.4)
- - React-jsinspector (0.72.4)
- - React-logger (0.72.4):
+ - RCT-Folly (= 2022.05.16.00)
+ - React-jsiexecutor (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
- glog
+ - hermes-engine
+ - RCT-Folly (= 2022.05.16.00)
+ - React-cxxreact (= 0.73.2)
+ - React-jsi (= 0.73.2)
+ - React-perflogger (= 0.73.2)
+ - React-jsinspector (0.73.2)
+ - React-logger (0.73.2):
+ - glog
+ - React-Mapbuffer (0.73.2):
+ - glog
+ - React-debug
- react-native-airship (15.3.1):
- AirshipFrameworkProxy (= 2.1.1)
- React-Core
@@ -600,8 +1168,6 @@ PODS:
- React-Core
- react-native-document-picker (8.2.1):
- React-Core
- - react-native-flipper (0.159.0):
- - React-Core
- react-native-geolocation (3.0.6):
- React-Core
- react-native-image-manipulator (1.0.5):
@@ -610,11 +1176,11 @@ PODS:
- React-Core
- react-native-key-command (1.0.6):
- React-Core
- - react-native-netinfo (9.3.10):
+ - react-native-netinfo (11.2.1):
- React-Core
- - react-native-pager-view (6.2.0):
+ - react-native-pager-view (6.2.2):
- React-Core
- - react-native-pdf (6.7.3):
+ - react-native-pdf (6.7.4):
- React-Core
- react-native-performance (5.1.0):
- React-Core
@@ -627,17 +1193,15 @@ PODS:
- React-Core
- react-native-render-html (6.3.1):
- React-Core
- - react-native-safe-area-context (4.4.1):
- - RCT-Folly
- - RCTRequired
- - RCTTypeSafety
+ - react-native-safe-area-context (4.7.4):
- React-Core
- - ReactCommon/turbomodule/core
- - react-native-view-shot (3.6.0):
+ - react-native-view-shot (3.8.0):
- React-Core
- - react-native-webview (11.23.0):
+ - react-native-webview (13.6.3):
- React-Core
- - React-NativeModulesApple (0.72.4):
+ - React-nativeconfig (0.73.2)
+ - React-NativeModulesApple (0.73.2):
+ - glog
- hermes-engine
- React-callinvoker
- React-Core
@@ -646,114 +1210,169 @@ PODS:
- React-runtimeexecutor
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- - React-perflogger (0.72.4)
- - React-RCTActionSheet (0.72.4):
- - React-Core/RCTActionSheetHeaders (= 0.72.4)
- - React-RCTAnimation (0.72.4):
- - RCT-Folly (= 2021.07.22.00)
- - RCTTypeSafety (= 0.72.4)
- - React-Codegen (= 0.72.4)
- - React-Core/RCTAnimationHeaders (= 0.72.4)
- - React-jsi (= 0.72.4)
- - ReactCommon/turbomodule/core (= 0.72.4)
- - React-RCTAppDelegate (0.72.4):
+ - React-perflogger (0.73.2)
+ - React-RCTActionSheet (0.73.2):
+ - React-Core/RCTActionSheetHeaders (= 0.73.2)
+ - React-RCTAnimation (0.73.2):
+ - RCT-Folly (= 2022.05.16.00)
+ - RCTTypeSafety
+ - React-Codegen
+ - React-Core/RCTAnimationHeaders
+ - React-jsi
+ - React-NativeModulesApple
+ - ReactCommon
+ - React-RCTAppDelegate (0.73.2):
- RCT-Folly
- RCTRequired
- RCTTypeSafety
- React-Core
- React-CoreModules
- React-hermes
+ - React-nativeconfig
- React-NativeModulesApple
+ - React-RCTFabric
- React-RCTImage
- React-RCTNetwork
- React-runtimescheduler
- - ReactCommon/turbomodule/core
- - React-RCTBlob (0.72.4):
+ - ReactCommon
+ - React-RCTBlob (0.73.2):
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
- - React-Codegen (= 0.72.4)
- - React-Core/RCTBlobHeaders (= 0.72.4)
- - React-Core/RCTWebSocket (= 0.72.4)
- - React-jsi (= 0.72.4)
- - React-RCTNetwork (= 0.72.4)
- - ReactCommon/turbomodule/core (= 0.72.4)
- - React-RCTImage (0.72.4):
- - RCT-Folly (= 2021.07.22.00)
- - RCTTypeSafety (= 0.72.4)
- - React-Codegen (= 0.72.4)
- - React-Core/RCTImageHeaders (= 0.72.4)
- - React-jsi (= 0.72.4)
- - React-RCTNetwork (= 0.72.4)
- - ReactCommon/turbomodule/core (= 0.72.4)
- - React-RCTLinking (0.72.4):
- - React-Codegen (= 0.72.4)
- - React-Core/RCTLinkingHeaders (= 0.72.4)
- - React-jsi (= 0.72.4)
- - ReactCommon/turbomodule/core (= 0.72.4)
- - React-RCTNetwork (0.72.4):
- - RCT-Folly (= 2021.07.22.00)
- - RCTTypeSafety (= 0.72.4)
- - React-Codegen (= 0.72.4)
- - React-Core/RCTNetworkHeaders (= 0.72.4)
- - React-jsi (= 0.72.4)
- - ReactCommon/turbomodule/core (= 0.72.4)
- - React-RCTSettings (0.72.4):
- - RCT-Folly (= 2021.07.22.00)
- - RCTTypeSafety (= 0.72.4)
- - React-Codegen (= 0.72.4)
- - React-Core/RCTSettingsHeaders (= 0.72.4)
- - React-jsi (= 0.72.4)
- - ReactCommon/turbomodule/core (= 0.72.4)
- - React-RCTText (0.72.4):
- - React-Core/RCTTextHeaders (= 0.72.4)
- - React-RCTVibration (0.72.4):
- - RCT-Folly (= 2021.07.22.00)
- - React-Codegen (= 0.72.4)
- - React-Core/RCTVibrationHeaders (= 0.72.4)
- - React-jsi (= 0.72.4)
- - ReactCommon/turbomodule/core (= 0.72.4)
- - React-rncore (0.72.4)
- - React-runtimeexecutor (0.72.4):
- - React-jsi (= 0.72.4)
- - React-runtimescheduler (0.72.4):
+ - RCT-Folly (= 2022.05.16.00)
+ - React-Codegen
+ - React-Core/RCTBlobHeaders
+ - React-Core/RCTWebSocket
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTNetwork
+ - ReactCommon
+ - React-RCTFabric (0.73.2):
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
+ - RCT-Folly/Fabric (= 2022.05.16.00)
+ - React-Core
+ - React-debug
+ - React-Fabric
+ - React-FabricImage
+ - React-graphics
+ - React-ImageManager
+ - React-jsi
+ - React-nativeconfig
+ - React-RCTImage
+ - React-RCTText
+ - React-rendererdebug
+ - React-runtimescheduler
+ - React-utils
+ - Yoga
+ - React-RCTImage (0.73.2):
+ - RCT-Folly (= 2022.05.16.00)
+ - RCTTypeSafety
+ - React-Codegen
+ - React-Core/RCTImageHeaders
+ - React-jsi
+ - React-NativeModulesApple
+ - React-RCTNetwork
+ - ReactCommon
+ - React-RCTLinking (0.73.2):
+ - React-Codegen
+ - React-Core/RCTLinkingHeaders (= 0.73.2)
+ - React-jsi (= 0.73.2)
+ - React-NativeModulesApple
+ - ReactCommon
+ - ReactCommon/turbomodule/core (= 0.73.2)
+ - React-RCTNetwork (0.73.2):
+ - RCT-Folly (= 2022.05.16.00)
+ - RCTTypeSafety
+ - React-Codegen
+ - React-Core/RCTNetworkHeaders
+ - React-jsi
+ - React-NativeModulesApple
+ - ReactCommon
+ - React-RCTSettings (0.73.2):
+ - RCT-Folly (= 2022.05.16.00)
+ - RCTTypeSafety
+ - React-Codegen
+ - React-Core/RCTSettingsHeaders
+ - React-jsi
+ - React-NativeModulesApple
+ - ReactCommon
+ - React-RCTText (0.73.2):
+ - React-Core/RCTTextHeaders (= 0.73.2)
+ - Yoga
+ - React-RCTVibration (0.73.2):
+ - RCT-Folly (= 2022.05.16.00)
+ - React-Codegen
+ - React-Core/RCTVibrationHeaders
+ - React-jsi
+ - React-NativeModulesApple
+ - ReactCommon
+ - React-rendererdebug (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - RCT-Folly (= 2022.05.16.00)
+ - React-debug
+ - React-rncore (0.73.2)
+ - React-runtimeexecutor (0.73.2):
+ - React-jsi (= 0.73.2)
+ - React-runtimescheduler (0.73.2):
+ - glog
+ - hermes-engine
+ - RCT-Folly (= 2022.05.16.00)
- React-callinvoker
+ - React-cxxreact
- React-debug
- React-jsi
+ - React-rendererdebug
- React-runtimeexecutor
- - React-utils (0.72.4):
+ - React-utils
+ - React-utils (0.73.2):
- glog
- - RCT-Folly (= 2021.07.22.00)
+ - RCT-Folly (= 2022.05.16.00)
- React-debug
- - ReactCommon/turbomodule/bridging (0.72.4):
+ - ReactCommon (0.73.2):
+ - React-logger (= 0.73.2)
+ - ReactCommon/turbomodule (= 0.73.2)
+ - ReactCommon/turbomodule (0.73.2):
- DoubleConversion
+ - fmt (~> 6.2.1)
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
- - React-callinvoker (= 0.72.4)
- - React-cxxreact (= 0.72.4)
- - React-jsi (= 0.72.4)
- - React-logger (= 0.72.4)
- - React-perflogger (= 0.72.4)
- - ReactCommon/turbomodule/core (0.72.4):
+ - RCT-Folly (= 2022.05.16.00)
+ - React-callinvoker (= 0.73.2)
+ - React-cxxreact (= 0.73.2)
+ - React-jsi (= 0.73.2)
+ - React-logger (= 0.73.2)
+ - React-perflogger (= 0.73.2)
+ - ReactCommon/turbomodule/bridging (= 0.73.2)
+ - ReactCommon/turbomodule/core (= 0.73.2)
+ - ReactCommon/turbomodule/bridging (0.73.2):
- DoubleConversion
+ - fmt (~> 6.2.1)
- glog
- hermes-engine
- - RCT-Folly (= 2021.07.22.00)
- - React-callinvoker (= 0.72.4)
- - React-cxxreact (= 0.72.4)
- - React-jsi (= 0.72.4)
- - React-logger (= 0.72.4)
- - React-perflogger (= 0.72.4)
+ - RCT-Folly (= 2022.05.16.00)
+ - React-callinvoker (= 0.73.2)
+ - React-cxxreact (= 0.73.2)
+ - React-jsi (= 0.73.2)
+ - React-logger (= 0.73.2)
+ - React-perflogger (= 0.73.2)
+ - ReactCommon/turbomodule/core (0.73.2):
+ - DoubleConversion
+ - fmt (~> 6.2.1)
+ - glog
+ - hermes-engine
+ - RCT-Folly (= 2022.05.16.00)
+ - React-callinvoker (= 0.73.2)
+ - React-cxxreact (= 0.73.2)
+ - React-jsi (= 0.73.2)
+ - React-logger (= 0.73.2)
+ - React-perflogger (= 0.73.2)
- RNAppleAuthentication (2.2.2):
- React-Core
- - RNCAsyncStorage (1.19.3):
+ - RNCAsyncStorage (1.21.0):
- React-Core
- RNCClipboard (1.12.1):
- React-Core
- - RNCPicker (2.4.4):
+ - RNCPicker (2.5.1):
- React-Core
- RNDeviceInfo (10.3.0):
- React-Core
@@ -776,11 +1395,13 @@ PODS:
- Firebase/Performance (= 8.8.0)
- React-Core
- RNFBApp
- - RNFlashList (1.6.1):
+ - RNFlashList (1.6.3):
- React-Core
- RNFS (2.20.0):
- React-Core
- - RNGestureHandler (2.12.0):
+ - RNGestureHandler (2.14.0):
+ - glog
+ - RCT-Folly (= 2022.05.16.00)
- React-Core
- RNGoogleSignin (10.0.1):
- GoogleSignIn (~> 7.0)
@@ -803,13 +1424,15 @@ PODS:
- RNReactNativeHapticFeedback (1.14.0):
- React-Core
- RNReanimated (3.6.1):
- - RCT-Folly (= 2021.07.22.00)
+ - glog
+ - RCT-Folly (= 2022.05.16.00)
- React-Core
- ReactCommon/turbomodule/core
- - RNScreens (3.21.0):
+ - RNScreens (3.29.0):
+ - glog
+ - RCT-Folly (= 2022.05.16.00)
- React-Core
- - React-RCTImage
- - RNSVG (13.14.0):
+ - RNSVG (14.0.0):
- React-Core
- SDWebImage (5.17.0):
- SDWebImage/Core (= 5.17.0)
@@ -823,46 +1446,43 @@ PODS:
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.17)
- SocketRocket (0.6.1)
- - Turf (2.6.1)
+ - Turf (2.7.0)
- VisionCamera (2.16.2):
- React
- React-callinvoker
- React-Core
- Yoga (1.14.0)
- - YogaKit (1.18.1):
- - Yoga (~> 1.14)
DEPENDENCIES:
- AirshipServiceExtension
- boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`)
- BVLinearGradient (from `../node_modules/react-native-linear-gradient`)
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
- - EXApplication (from `../node_modules/expo-application/ios`)
- Expo (from `../node_modules/expo`)
- ExpoImage (from `../node_modules/expo-image/ios`)
- ExpoModulesCore (from `../node_modules/expo-modules-core`)
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
- FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`)
- - Flipper (= 0.182.0)
+ - Flipper (= 0.201.0)
- Flipper-Boost-iOSX (= 1.76.0.1.11)
- Flipper-DoubleConversion (= 3.2.0.1)
- Flipper-Fmt (= 7.1.7)
- Flipper-Folly (= 2.6.10)
- Flipper-Glog (= 0.5.0.5)
- Flipper-PeerTalk (= 0.0.4)
- - FlipperKit (= 0.182.0)
- - FlipperKit/Core (= 0.182.0)
- - FlipperKit/CppBridge (= 0.182.0)
- - FlipperKit/FBCxxFollyDynamicConvert (= 0.182.0)
- - FlipperKit/FBDefines (= 0.182.0)
- - FlipperKit/FKPortForwarding (= 0.182.0)
- - FlipperKit/FlipperKitHighlightOverlay (= 0.182.0)
- - FlipperKit/FlipperKitLayoutPlugin (= 0.182.0)
- - FlipperKit/FlipperKitLayoutTextSearchable (= 0.182.0)
- - FlipperKit/FlipperKitNetworkPlugin (= 0.182.0)
- - FlipperKit/FlipperKitReactPlugin (= 0.182.0)
- - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.182.0)
- - FlipperKit/SKIOSNetworkPlugin (= 0.182.0)
+ - FlipperKit (= 0.201.0)
+ - FlipperKit/Core (= 0.201.0)
+ - FlipperKit/CppBridge (= 0.201.0)
+ - FlipperKit/FBCxxFollyDynamicConvert (= 0.201.0)
+ - FlipperKit/FBDefines (= 0.201.0)
+ - FlipperKit/FKPortForwarding (= 0.201.0)
+ - FlipperKit/FlipperKitHighlightOverlay (= 0.201.0)
+ - FlipperKit/FlipperKitLayoutPlugin (= 0.201.0)
+ - FlipperKit/FlipperKitLayoutTextSearchable (= 0.201.0)
+ - FlipperKit/FlipperKitNetworkPlugin (= 0.201.0)
+ - FlipperKit/FlipperKitReactPlugin (= 0.201.0)
+ - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.201.0)
+ - FlipperKit/SKIOSNetworkPlugin (= 0.201.0)
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
- hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`)
- libevent (~> 2.1.12)
@@ -870,6 +1490,7 @@ DEPENDENCIES:
- "onfido-react-native-sdk (from `../node_modules/@onfido/react-native-sdk`)"
- OpenSSL-Universal (= 1.1.1100)
- RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
+ - RCT-Folly/Fabric (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
- React (from `../node_modules/react-native/`)
@@ -881,17 +1502,22 @@ DEPENDENCIES:
- React-CoreModules (from `../node_modules/react-native/React/CoreModules`)
- React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`)
- React-debug (from `../node_modules/react-native/ReactCommon/react/debug`)
+ - React-Fabric (from `../node_modules/react-native/ReactCommon`)
+ - React-FabricImage (from `../node_modules/react-native/ReactCommon`)
+ - React-graphics (from `../node_modules/react-native/ReactCommon/react/renderer/graphics`)
- React-hermes (from `../node_modules/react-native/ReactCommon/hermes`)
+ - React-ImageManager (from `../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios`)
+ - React-jserrorhandler (from `../node_modules/react-native/ReactCommon/jserrorhandler`)
- React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
- - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
+ - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector-modern`)
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
+ - React-Mapbuffer (from `../node_modules/react-native/ReactCommon`)
- "react-native-airship (from `../node_modules/@ua/react-native-airship`)"
- react-native-blob-util (from `../node_modules/react-native-blob-util`)
- "react-native-cameraroll (from `../node_modules/@react-native-camera-roll/camera-roll`)"
- react-native-config (from `../node_modules/react-native-config`)
- react-native-document-picker (from `../node_modules/react-native-document-picker`)
- - react-native-flipper (from `../node_modules/react-native-flipper`)
- "react-native-geolocation (from `../node_modules/@react-native-community/geolocation`)"
- "react-native-image-manipulator (from `../node_modules/@oguzhnatly/react-native-image-manipulator`)"
- react-native-image-picker (from `../node_modules/react-native-image-picker`)
@@ -906,18 +1532,21 @@ DEPENDENCIES:
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- react-native-view-shot (from `../node_modules/react-native-view-shot`)
- react-native-webview (from `../node_modules/react-native-webview`)
+ - React-nativeconfig (from `../node_modules/react-native/ReactCommon`)
- React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
- React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`)
- React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
- React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`)
- React-RCTAppDelegate (from `../node_modules/react-native/Libraries/AppDelegate`)
- React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`)
+ - React-RCTFabric (from `../node_modules/react-native/React`)
- React-RCTImage (from `../node_modules/react-native/Libraries/Image`)
- React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`)
- React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`)
- React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`)
- React-RCTText (from `../node_modules/react-native/Libraries/Text`)
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
+ - React-rendererdebug (from `../node_modules/react-native/ReactCommon/react/renderer/debug`)
- React-rncore (from `../node_modules/react-native/ReactCommon`)
- React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`)
- React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`)
@@ -999,7 +1628,6 @@ SPEC REPOS:
- SDWebImageWebPCoder
- SocketRocket
- Turf
- - YogaKit
EXTERNAL SOURCES:
boost:
@@ -1008,8 +1636,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-linear-gradient"
DoubleConversion:
:podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
- EXApplication:
- :path: "../node_modules/expo-application/ios"
Expo:
:path: "../node_modules/expo"
ExpoImage:
@@ -1024,7 +1650,7 @@ EXTERNAL SOURCES:
:podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec"
hermes-engine:
:podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec"
- :tag: hermes-2023-08-07-RNv0.72.4-813b2def12bc9df02654b3e3653ae4a68d0572e0
+ :tag: hermes-2023-11-17-RNv0.73.0-21043a3fc062be445e56a2c10ecd8be028dd9cc5
lottie-react-native:
:path: "../node_modules/lottie-react-native"
onfido-react-native-sdk:
@@ -1049,16 +1675,28 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/cxxreact"
React-debug:
:path: "../node_modules/react-native/ReactCommon/react/debug"
+ React-Fabric:
+ :path: "../node_modules/react-native/ReactCommon"
+ React-FabricImage:
+ :path: "../node_modules/react-native/ReactCommon"
+ React-graphics:
+ :path: "../node_modules/react-native/ReactCommon/react/renderer/graphics"
React-hermes:
:path: "../node_modules/react-native/ReactCommon/hermes"
+ React-ImageManager:
+ :path: "../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios"
+ React-jserrorhandler:
+ :path: "../node_modules/react-native/ReactCommon/jserrorhandler"
React-jsi:
:path: "../node_modules/react-native/ReactCommon/jsi"
React-jsiexecutor:
:path: "../node_modules/react-native/ReactCommon/jsiexecutor"
React-jsinspector:
- :path: "../node_modules/react-native/ReactCommon/jsinspector"
+ :path: "../node_modules/react-native/ReactCommon/jsinspector-modern"
React-logger:
:path: "../node_modules/react-native/ReactCommon/logger"
+ React-Mapbuffer:
+ :path: "../node_modules/react-native/ReactCommon"
react-native-airship:
:path: "../node_modules/@ua/react-native-airship"
react-native-blob-util:
@@ -1069,8 +1707,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-config"
react-native-document-picker:
:path: "../node_modules/react-native-document-picker"
- react-native-flipper:
- :path: "../node_modules/react-native-flipper"
react-native-geolocation:
:path: "../node_modules/@react-native-community/geolocation"
react-native-image-manipulator:
@@ -1099,6 +1735,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-view-shot"
react-native-webview:
:path: "../node_modules/react-native-webview"
+ React-nativeconfig:
+ :path: "../node_modules/react-native/ReactCommon"
React-NativeModulesApple:
:path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios"
React-perflogger:
@@ -1111,6 +1749,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/Libraries/AppDelegate"
React-RCTBlob:
:path: "../node_modules/react-native/Libraries/Blob"
+ React-RCTFabric:
+ :path: "../node_modules/react-native/React"
React-RCTImage:
:path: "../node_modules/react-native/Libraries/Image"
React-RCTLinking:
@@ -1123,6 +1763,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/Libraries/Text"
React-RCTVibration:
:path: "../node_modules/react-native/Libraries/Vibration"
+ React-rendererdebug:
+ :path: "../node_modules/react-native/ReactCommon/react/renderer/debug"
React-rncore:
:path: "../node_modules/react-native/ReactCommon"
React-runtimeexecutor:
@@ -1185,16 +1827,15 @@ SPEC CHECKSUMS:
AirshipFrameworkProxy: ea1b6c665c798637b93c465b5e505be3011f1d9d
AirshipServiceExtension: 89c6e25a69f3458d9dbd581c700cffb196b61930
AppAuth: 3bb1d1cd9340bd09f5ed189fb00b1cc28e1e8570
- boost: 57d2868c099736d80fcd648bf211b4431e51a558
+ boost: d3f49c53809116a5d38da093a8aa78bf551aed09
BVLinearGradient: 421743791a59d259aec53f4c58793aad031da2ca
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
- DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
- EXApplication: 042aa2e3f05258a16962ea1a9914bf288db9c9a1
- Expo: 61a8e1aa94311557c137c0a4dfd4fe78281cfbb4
- ExpoImage: e35fb1acb84c01575b4f5c5f6260906639a3320b
- ExpoModulesCore: c480fd4e3c7c8e81f0a6ba3a7c56869f25fe016d
- FBLazyVector: 5d4a3b7f411219a45a6d952f77d2c0a6c9989da5
- FBReactNativeSpec: 3fc2d478e1c4b08276f9dd9128f80ec6d5d85c1f
+ DoubleConversion: fea03f2699887d960129cc54bba7e52542b6f953
+ Expo: cd2dc043dd1cc3d9e8e4e035fb9a41b421e8f13f
+ ExpoImage: 1cdaa65a6a70bb01067e21ad1347ff2d973885f5
+ ExpoModulesCore: 01c0abfa6cd9c41c4bd76d8a1a079e6b591db10f
+ FBLazyVector: fbc4957d9aa695250b55d879c1d86f79d7e69ab4
+ FBReactNativeSpec: 86de768f89901ef6ed3207cd686362189d64ac88
Firebase: 629510f1a9ddb235f3a7c5c8ceb23ba887f0f814
FirebaseABTesting: 10cbce8db9985ae2e3847ea44e9947dd18f94e10
FirebaseAnalytics: 5506ea8b867d8423485a84b4cd612d279f7b0b8a
@@ -1204,123 +1845,130 @@ SPEC CHECKSUMS:
FirebaseInstallations: 40bd9054049b2eae9a2c38ef1c3dd213df3605cd
FirebasePerformance: 0c01a7a496657d7cea86d40c0b1725259d164c6c
FirebaseRemoteConfig: 2d6e2cfdb49af79535c8af8a80a4a5009038ec2b
- Flipper: 6edb735e6c3e332975d1b17956bcc584eccf5818
+ Flipper: c7a0093234c4bdd456e363f2f19b2e4b27652d44
Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c
Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30
Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b
Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3
Flipper-Glog: 70c50ce58ddaf67dc35180db05f191692570f446
Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9
- FlipperKit: 2efad7007d6745a3f95e4034d547be637f89d3f6
+ FlipperKit: 37525a5d056ef9b93d1578e04bc3ea1de940094f
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
- glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
+ glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2
GoogleAppMeasurement: 5ba1164e3c844ba84272555e916d0a6d3d977e91
- GoogleDataTransport: f0308f5905a745f94fb91fea9c6cbaf3831cb1bd
+ GoogleDataTransport: 57c22343ab29bc686febbf7cbb13bad167c2d8fe
GoogleSignIn: b232380cf495a429b8095d3178a8d5855b42e842
- GoogleUtilities: 9aa0ad5a7bc171f8bae016300bfcfa3fb8425749
+ GoogleUtilities: 0759d1a57ebb953965c2dfe0ba4c82e95ccc2e34
GTMAppAuth: 99fb010047ba3973b7026e45393f51f27ab965ae
- GTMSessionFetcher: e8647203b65cee28c5f73d0f473d096653945e72
- hermes-engine: 81191603c4eaa01f5e4ae5737a9efcf64756c7b2
+ GTMSessionFetcher: 41b9ef0b4c08a6db4b7eb51a21ae5183ec99a2c8
+ hermes-engine: b361c9ef5ef3cda53f66e195599b47e1f84ffa35
libaom: 144606b1da4b5915a1054383c3a4459ccdb3c661
libavif: 84bbb62fb232c3018d6f1bab79beea87e35de7b7
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
libvmaf: 27f523f1e63c694d14d534cd0fddd2fab0ae8711
libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009
- lottie-ios: 25e7b2675dad5c3ddad369ac9baab03560c5bfdd
- lottie-react-native: 3a3084faddd3891c276f23fd6e797b83f2021bbc
+ lottie-ios: 3d98679b41fa6fd6aff2352b3953dbd3df8a397e
+ lottie-react-native: a2ae9c27c273b060b2affff2957bc0ff7fdca353
MapboxCommon: 4a0251dd470ee37e7fadda8e285c01921a5e1eb0
MapboxCoreMaps: eb07203bbb0b1509395db5ab89cd3ad6c2e3c04c
MapboxMaps: af50ec61a7eb3b032c3f7962c6bd671d93d2a209
MapboxMobileEvents: de50b3a4de180dd129c326e09cd12c8adaaa46d6
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
- Onfido: c7d010d9793790d44a07799d9be25aa8e3814ee7
+ Onfido: 564f60c39819635ec5b549285a1eec278cc9ba67
onfido-react-native-sdk: b346a620af5669f9fecb6dc3052314a35a94ad9f
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
Plaid: 431ef9be5314a1345efb451bc5e6b067bfb3b4c6
- PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef
- RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
- RCTRequired: c0569ecc035894e4a68baecb30fe6a7ea6e399f9
- RCTTypeSafety: e90354072c21236e0bcf1699011e39acd25fea2f
- React: a1be3c6dc0a6e949ccd3e659781aa47bbae1868f
- React-callinvoker: 1020b33f6cb1a1824f9ca2a86609fbce2a73c6ed
- React-Codegen: a0a26badf098d4a779acda922caf74f6ecabed28
- React-Core: 52075b80f10c26f62219d7b5d13d7d8089f027b3
- React-CoreModules: 21abab85d7ad9038ce2b1c33d39e3baaf7dc9244
- React-cxxreact: 4ad1cc861e32fb533dad6ff7a4ea25680fa1c994
- React-debug: 17366a3d5c5d2f5fc04f09101a4af38cb42b54ae
- React-hermes: 37377d0a56aa0cf55c65248271866ce3268cde3f
- React-jsi: 6de8b0ccc6b765b58e4eee9ee38049dbeaf5c221
- React-jsiexecutor: c7f826e40fa9cab5d37cab6130b1af237332b594
- React-jsinspector: aaed4cf551c4a1c98092436518c2d267b13a673f
- React-logger: da1ebe05ae06eb6db4b162202faeafac4b435e77
+ PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4
+ RCT-Folly: 7169b2b1c44399c76a47b5deaaba715eeeb476c0
+ RCTRequired: 9b1e7e262745fb671e33c51c1078d093bd30e322
+ RCTTypeSafety: a759e3b086eccf3e2cbf2493d22f28e082f958e6
+ React: 805f5dd55bbdb92c36b4914c64aaae4c97d358dc
+ React-callinvoker: 6a697867607c990c2c2c085296ee32cfb5e47c01
+ React-Codegen: c4447ffa339f4e7a22e0c9c800eec9084f31899c
+ React-Core: 49f66fecc7695464e9b7bc7dc7cd9473d2c60584
+ React-CoreModules: 710e7c557a1a8180bd1645f5b4bf79f4bd3f5417
+ React-cxxreact: 345857b5e4be000c0527df78be3b41a0677a20ce
+ React-debug: f1637bce73342b2f6eee4982508fdfb088667a87
+ React-Fabric: 4dfcff8f14d8e5a7a60b11b7862dad2a9d99c65b
+ React-FabricImage: 4a9e9510b7f28bbde6a743b18c0cb941a142e938
+ React-graphics: dd5af9d8b1b45171fd6933e19fed522f373bcb10
+ React-hermes: a52d183a5cf8ccb7020ce3df4275b89d01e6b53e
+ React-ImageManager: c5b7db131eff71443d7f3a8d686fd841d18befd3
+ React-jserrorhandler: 97a6a12e2344c3c4fdd7ba1edefb005215c732f8
+ React-jsi: a182068133f80918cd0eec77875abaf943a0b6be
+ React-jsiexecutor: dacd00ce8a18fc00a0ae6c25e3015a6437e5d2e8
+ React-jsinspector: 03644c063fc3621c9a4e8bf263a8150909129618
+ React-logger: 66b168e2b2bee57bd8ce9e69f739d805732a5570
+ React-Mapbuffer: 9ee041e1d7be96da6d76a251f92e72b711c651d6
react-native-airship: 6ded22e4ca54f2f80db80b7b911c2b9b696d9335
react-native-blob-util: 99f4d79189252f597fe0d810c57a3733b1b1dea6
react-native-cameraroll: 8ffb0af7a5e5de225fd667610e2979fc1f0c2151
react-native-config: 7cd105e71d903104e8919261480858940a6b9c0e
react-native-document-picker: 69ca2094d8780cfc1e7e613894d15290fdc54bba
- react-native-flipper: dc5290261fbeeb2faec1bdc57ae6dd8d562e1de4
react-native-geolocation: 0f7fe8a4c2de477e278b0365cce27d089a8c5903
react-native-image-manipulator: c48f64221cfcd46e9eec53619c4c0374f3328a56
react-native-image-picker: c33d4e79f0a14a2b66e5065e14946ae63749660b
react-native-key-command: 5af6ee30ff4932f78da6a2109017549042932aa5
- react-native-netinfo: ccbe1085dffd16592791d550189772e13bf479e2
- react-native-pager-view: 0ccb8bf60e2ebd38b1f3669fa3650ecce81db2df
- react-native-pdf: b4ca3d37a9a86d9165287741c8b2ef4d8940c00e
+ react-native-netinfo: 8a7fd3f7130ef4ad2fb4276d5c9f8d3f28d2df3d
+ react-native-pager-view: 02a5c4962530f7efc10dd51ee9cdabeff5e6c631
+ react-native-pdf: 79aa75e39a80c1d45ffe58aa500f3cf08f267a2e
react-native-performance: cef2b618d47b277fb5c3280b81a3aad1e72f2886
react-native-plaid-link-sdk: df1618a85a615d62ff34e34b76abb7a56497fbc1
react-native-quick-sqlite: bcc7a7a250a40222f18913a97cd356bf82d0a6c4
react-native-render-html: 96c979fe7452a0a41559685d2f83b12b93edac8c
- react-native-safe-area-context: 99b24a0c5acd0d5dcac2b1a7f18c49ea317be99a
- react-native-view-shot: 705f999ac2a24e4e6c909c0ca65c732ed33ca2ff
- react-native-webview: e771bc375f789ebfa02a26939a57dbc6fa897336
- React-NativeModulesApple: edb5ace14f73f4969df6e7b1f3e41bef0012740f
- React-perflogger: 496a1a3dc6737f964107cb3ddae7f9e265ddda58
- React-RCTActionSheet: 02904b932b50e680f4e26e7a686b33ebf7ef3c00
- React-RCTAnimation: 88feaf0a85648fb8fd497ce749829774910276d6
- React-RCTAppDelegate: 5792ac0f0feccb584765fdd7aa81ea320c4d9b0b
- React-RCTBlob: 0dbc9e2a13d241b37d46b53e54630cbad1f0e141
- React-RCTImage: b111645ab901f8e59fc68fbe31f5731bdbeef087
- React-RCTLinking: 3d719727b4c098aad3588aa3559361ee0579f5de
- React-RCTNetwork: b44d3580be05d74556ba4efbf53570f17e38f734
- React-RCTSettings: c0c54b330442c29874cd4dae6e94190dc11a6f6f
- React-RCTText: 9b9f5589d9b649d7246c3f336e116496df28cfe6
- React-RCTVibration: 691c67f3beaf1d084ceed5eb5c1dddd9afa8591e
- React-rncore: 142268f6c92e296dc079aadda3fade778562f9e4
- React-runtimeexecutor: d465ba0c47ef3ed8281143f59605cacc2244d5c7
- React-runtimescheduler: 4941cc1b3cf08b792fbf666342c9fc95f1969035
- React-utils: b79f2411931f9d3ea5781404dcbb2fa8a837e13a
- ReactCommon: 4b2bdcb50a3543e1c2b2849ad44533686610826d
+ react-native-safe-area-context: 2cd91d532de12acdb0a9cbc8d43ac72a8e4c897c
+ react-native-view-shot: 6b7ed61d77d88580fed10954d45fad0eb2d47688
+ react-native-webview: 88293a0f23eca8465c0433c023ec632930e644d0
+ React-nativeconfig: d753fbbc8cecc8ae413d615599ac378bbf6999bb
+ React-NativeModulesApple: 964f4eeab1b4325e8b6a799cf4444c3fd4eb0a9c
+ React-perflogger: 29efe63b7ef5fbaaa50ef6eaa92482f98a24b97e
+ React-RCTActionSheet: 69134c62aefd362027b20da01cd5d14ffd39db3f
+ React-RCTAnimation: 3b5a57087c7a5e727855b803d643ac1d445488f5
+ React-RCTAppDelegate: a3ce9b69c0620a1717d08e826d4dc7ad8a3a3cae
+ React-RCTBlob: 26ea660f2be1e6de62f2d2ad9a9c7b9bfabb786f
+ React-RCTFabric: bb6dbbff2f80b9489f8b2f1d2554aa040aa2e3cd
+ React-RCTImage: 27b27f4663df9e776d0549ed2f3536213e793f1b
+ React-RCTLinking: 962880ce9d0e2ea83fd182953538fc4ed757d4da
+ React-RCTNetwork: 73a756b44d4ad584bae13a5f1484e3ce12accac8
+ React-RCTSettings: 6d7f8d807f05de3d01cfb182d14e5f400716faac
+ React-RCTText: 73006e95ca359595c2510c1c0114027c85a6ddd3
+ React-RCTVibration: 599f427f9cbdd9c4bf38959ca020e8fef0717211
+ React-rendererdebug: f2946e0a1c3b906e71555a7c4a39aa6a6c0e639b
+ React-rncore: 74030de0ffef7b1a3fb77941168624534cc9ae7f
+ React-runtimeexecutor: 2d1f64f58193f00a3ad71d3f89c2bfbfe11cf5a5
+ React-runtimescheduler: df8945a656356ff10f58f65a70820478bfcf33ad
+ React-utils: f5bc61e7ea3325c0732ae2d755f4441940163b85
+ ReactCommon: 45b5d4f784e869c44a6f5a8fad5b114ca8f78c53
RNAppleAuthentication: 0571c08da8c327ae2afc0261b48b4a515b0286a6
- RNCAsyncStorage: c913ede1fa163a71cea118ed4670bbaaa4b511bb
+ RNCAsyncStorage: 618d03a5f52fbccb3d7010076bc54712844c18ef
RNCClipboard: d77213bfa269013bf4b857b7a9ca37ee062d8ef1
- RNCPicker: 0b65be85fe7954fbb2062ef079e3d1cde252d888
+ RNCPicker: 529d564911e93598cc399b56cc0769ce3675f8c8
RNDeviceInfo: 4701f0bf2a06b34654745053db0ce4cb0c53ada7
RNDevMenu: 72807568fe4188bd4c40ce32675d82434b43c45d
RNFBAnalytics: f76bfa164ac235b00505deb9fc1776634056898c
RNFBApp: 729c0666395b1953198dc4a1ec6deb8fbe1c302e
RNFBCrashlytics: 2061ca863e8e2fa1aae9b12477d7dfa8e88ca0f9
RNFBPerf: 389914cda4000fe0d996a752532a591132cbf3f9
- RNFlashList: 236646d48f224a034f35baa0242e1b77db063b1e
+ RNFlashList: 4b4b6b093afc0df60ae08f9cbf6ccd4c836c667a
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
- RNGestureHandler: dec4645026e7401a0899f2846d864403478ff6a5
+ RNGestureHandler: 61bfdfc05db9b79dd61f894dcd29d3dcc6db3c02
RNGoogleSignin: ccaa4a81582cf713eea562c5dd9dc1961a715fd0
RNLocalize: d4b8af4e442d4bcca54e68fc687a2129b4d71a81
rnmapbox-maps: 6f638ec002aa6e906a6f766d69cd45f968d98e64
RNPermissions: 9b086c8f05b2e2faa587fdc31f4c5ab4509728aa
RNReactNativeHapticFeedback: 1e3efeca9628ff9876ee7cdd9edec1b336913f8c
- RNReanimated: fdbaa9c964bbab7fac50c90862b6cc5f041679b9
- RNScreens: d037903436160a4b039d32606668350d2a808806
- RNSVG: d00c8f91c3cbf6d476451313a18f04d220d4f396
+ RNReanimated: 57f436e7aa3d277fbfed05e003230b43428157c0
+ RNScreens: b582cb834dc4133307562e930e8fa914b8c04ef2
+ RNSVG: 255767813dac22db1ec2062c8b7e7b856d4e5ae6
SDWebImage: 750adf017a315a280c60fde706ab1e552a3ae4e9
SDWebImageAVIFCoder: 8348fef6d0ec69e129c66c9fe4d74fbfbf366112
SDWebImageSVGCoder: 15a300a97ec1c8ac958f009c02220ac0402e936c
SDWebImageWebPCoder: af09429398d99d524cae2fe00f6f0f6e491ed102
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
- Turf: 469ce2c3d22e5e8e4818d5a3b254699a5c89efa4
- VisionCamera: 95f969b8950b411285579d633a1014782fe0e634
- Yoga: 3efc43e0d48686ce2e8c60f99d4e6bd349aff981
- YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
+ Turf: 13d1a92d969ca0311bbc26e8356cca178ce95da2
+ VisionCamera: 7d13aae043ffb38b224a0f725d1e23ca9c190fe7
+ Yoga: 13c8ef87792450193e117976337b8527b49e8c03
-PODFILE CHECKSUM: c403784ee1fdf281bcc552696504207f3022cb66
+PODFILE CHECKSUM: 0ccbb4f2406893c6e9f266dc1e7470dcd72885d2
-COCOAPODS: 1.12.1
+COCOAPODS: 1.13.0
diff --git a/package-lock.json b/package-lock.json
index 15964d8c5f3e..b530468d7725 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "new.expensify",
- "version": "1.4.21-4",
+ "version": "1.4.25-1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "new.expensify",
- "version": "1.4.21-4",
+ "version": "1.4.25-1",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -23,23 +23,23 @@
"@kie/mock-github": "^1.0.0",
"@oguzhnatly/react-native-image-manipulator": "github:Expensify/react-native-image-manipulator#5cdae3d4455b03a04c57f50be3863e2fe6c92c52",
"@onfido/react-native-sdk": "8.3.0",
- "@react-native-async-storage/async-storage": "^1.17.10",
+ "@react-native-async-storage/async-storage": "^1.19.5",
"@react-native-camera-roll/camera-roll": "5.4.0",
"@react-native-clipboard/clipboard": "^1.12.1",
"@react-native-community/geolocation": "^3.0.6",
- "@react-native-community/netinfo": "^9.3.10",
+ "@react-native-community/netinfo": "11.2.1",
"@react-native-firebase/analytics": "^12.3.0",
"@react-native-firebase/app": "^12.3.0",
"@react-native-firebase/crashlytics": "^12.3.0",
"@react-native-firebase/perf": "^12.3.0",
"@react-native-google-signin/google-signin": "^10.0.1",
- "@react-native-picker/picker": "^2.4.3",
+ "@react-native-picker/picker": "2.5.1",
"@react-navigation/material-top-tabs": "^6.6.3",
"@react-navigation/native": "6.1.8",
"@react-navigation/stack": "6.3.16",
"@react-ng/bounds-observer": "^0.2.1",
"@rnmapbox/maps": "^10.0.11",
- "@shopify/flash-list": "^1.6.1",
+ "@shopify/flash-list": "^1.6.3",
"@types/node": "^18.14.0",
"@ua/react-native-airship": "^15.3.1",
"@vue/preload-webpack-plugin": "^2.0.0",
@@ -51,16 +51,16 @@
"date-fns-tz": "^2.0.0",
"dom-serializer": "^0.2.2",
"domhandler": "^4.3.0",
- "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#398bf7c6a6d37f229a41d92bd7a4324c0fd32849",
- "expo": "^49.0.0",
- "expo-image": "1.8.1",
+ "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#c6bb3cfa56d12af9fa02e2bfc729646f5b64ef44",
+ "expo": "^50.0.0-preview.7",
+ "expo-image": "1.10.1",
"fbjs": "^3.0.2",
"htmlparser2": "^7.2.0",
"idb-keyval": "^6.2.1",
- "jest-expo": "^49.0.0",
+ "jest-expo": "50.0.1",
"jest-when": "^3.5.2",
"lodash": "4.17.21",
- "lottie-react-native": "^6.4.0",
+ "lottie-react-native": "6.4.1",
"mapbox-gl": "^2.15.0",
"onfido-sdk-ui": "13.1.0",
"patch-package": "^8.0.0",
@@ -74,7 +74,7 @@
"react-dom": "18.1.0",
"react-error-boundary": "^4.0.11",
"react-map-gl": "^7.1.3",
- "react-native": "0.72.4",
+ "react-native": "0.73.2",
"react-native-android-location-enabler": "^1.2.2",
"react-native-blob-util": "^0.17.3",
"react-native-collapsible": "^1.6.1",
@@ -84,7 +84,7 @@
"react-native-document-picker": "^8.2.1",
"react-native-draggable-flatlist": "^4.0.1",
"react-native-fs": "^2.20.0",
- "react-native-gesture-handler": "2.12.0",
+ "react-native-gesture-handler": "2.14.0",
"react-native-google-places-autocomplete": "2.5.6",
"react-native-haptic-feedback": "^1.13.0",
"react-native-image-pan-zoom": "^2.1.12",
@@ -94,9 +94,9 @@
"react-native-linear-gradient": "^2.8.1",
"react-native-localize": "^2.2.6",
"react-native-modal": "^13.0.0",
- "react-native-onyx": "1.0.118",
- "react-native-pager-view": "^6.2.0",
- "react-native-pdf": "^6.7.3",
+ "react-native-onyx": "1.0.126",
+ "react-native-pager-view": "6.2.2",
+ "react-native-pdf": "^6.7.4",
"react-native-performance": "^5.1.0",
"react-native-permissions": "^3.9.3",
"react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#7a407cd4174d9838a944c1c2e1cb4a9737ac69c5",
@@ -105,16 +105,16 @@
"react-native-quick-sqlite": "^8.0.0-beta.2",
"react-native-reanimated": "^3.6.1",
"react-native-render-html": "6.3.1",
- "react-native-safe-area-context": "4.4.1",
- "react-native-screens": "3.21.0",
- "react-native-svg": "^13.13.0",
+ "react-native-safe-area-context": "4.7.4",
+ "react-native-screens": "3.29.0",
+ "react-native-svg": "14.0.0",
"react-native-tab-view": "^3.5.2",
"react-native-url-polyfill": "^2.0.0",
- "react-native-view-shot": "^3.6.0",
+ "react-native-view-shot": "3.8.0",
"react-native-vision-camera": "^2.16.2",
"react-native-web": "^0.19.9",
"react-native-web-linear-gradient": "^1.1.2",
- "react-native-webview": "^11.17.2",
+ "react-native-webview": "13.6.3",
"react-pdf": "^6.2.2",
"react-plaid-link": "3.3.2",
"react-web-config": "^1.0.0",
@@ -147,7 +147,8 @@
"@octokit/plugin-paginate-rest": "3.1.0",
"@octokit/plugin-throttling": "4.1.0",
"@react-native-community/eslint-config": "3.0.0",
- "@react-native/metro-config": "^0.72.11",
+ "@react-native/babel-preset": "^0.73.19",
+ "@react-native/metro-config": "^0.73.3",
"@react-navigation/devtools": "^6.0.10",
"@storybook/addon-a11y": "^6.5.9",
"@storybook/addon-essentials": "^7.0.0",
@@ -161,6 +162,7 @@
"@testing-library/jest-native": "5.4.1",
"@testing-library/react-native": "11.5.1",
"@trivago/prettier-plugin-sort-imports": "^4.2.0",
+ "@types/canvas-size": "^1.2.2",
"@types/concurrently": "^7.0.0",
"@types/jest": "^29.5.2",
"@types/jest-when": "^3.5.2",
@@ -168,7 +170,7 @@
"@types/lodash": "^4.14.195",
"@types/mapbox-gl": "^2.7.13",
"@types/pusher-js": "^5.1.0",
- "@types/react": "^18.2.12",
+ "@types/react": "18.2.45",
"@types/react-beautiful-dnd": "^13.1.4",
"@types/react-collapse": "^5.0.1",
"@types/react-dom": "^18.2.4",
@@ -216,13 +218,11 @@
"jest-environment-jsdom": "^29.4.1",
"jest-transformer-svg": "^2.0.1",
"memfs": "^4.6.0",
- "metro-react-native-babel-preset": "0.76.8",
"onchange": "^7.1.0",
"portfinder": "^1.0.28",
"prettier": "^2.8.8",
"pusher-js-mock": "^0.3.3",
"react-native-clean-project": "^4.0.0-alpha4.0",
- "react-native-flipper": "https://gitpkg.now.sh/facebook/flipper/react-native/react-native-flipper?9cacc9b59402550eae866e0e81e5f0c2f8203e6b",
"react-native-performance-flipper-reporter": "^2.0.0",
"react-test-renderer": "18.2.0",
"reassure": "^0.10.1",
@@ -532,14 +532,14 @@
"license": "ISC"
},
"node_modules/@babel/helper-create-class-features-plugin": {
- "version": "7.22.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.9.tgz",
- "integrity": "sha512-Pwyi89uO4YrGKxL/eNJ8lfEH55DnRloGPOseaA8NFNL6jAUnn+KccaISiFazCj5IolPPDjGSdzQzXVzODVRqUQ==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz",
+ "integrity": "sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==",
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-environment-visitor": "^7.22.5",
"@babel/helper-function-name": "^7.22.5",
- "@babel/helper-member-expression-to-functions": "^7.22.5",
+ "@babel/helper-member-expression-to-functions": "^7.22.15",
"@babel/helper-optimise-call-expression": "^7.22.5",
"@babel/helper-replace-supers": "^7.22.9",
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
@@ -640,22 +640,22 @@
}
},
"node_modules/@babel/helper-member-expression-to-functions": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.5.tgz",
- "integrity": "sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz",
+ "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==",
"dependencies": {
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.23.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-imports": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz",
- "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz",
+ "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==",
"dependencies": {
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.22.15"
},
"engines": {
"node": ">=6.9.0"
@@ -765,9 +765,9 @@
}
},
"node_modules/@babel/helper-string-parser": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
- "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
+ "version": "7.23.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
+ "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==",
"engines": {
"node": ">=6.9.0"
}
@@ -781,9 +781,9 @@
}
},
"node_modules/@babel/helper-validator-option": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz",
- "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==",
+ "version": "7.23.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz",
+ "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==",
"engines": {
"node": ">=6.9.0"
}
@@ -934,6 +934,7 @@
},
"node_modules/@babel/plugin-proposal-export-namespace-from": {
"version": "7.18.9",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.18.9",
@@ -1246,9 +1247,9 @@
}
},
"node_modules/@babel/plugin-syntax-jsx": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz",
- "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==",
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz",
+ "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==",
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -1607,9 +1608,9 @@
}
},
"node_modules/@babel/plugin-transform-export-namespace-from": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.5.tgz",
- "integrity": "sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg==",
+ "version": "7.23.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz",
+ "integrity": "sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==",
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-export-namespace-from": "^7.8.3"
@@ -1924,9 +1925,9 @@
}
},
"node_modules/@babel/plugin-transform-parameters": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz",
- "integrity": "sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg==",
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz",
+ "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==",
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@@ -1953,12 +1954,12 @@
}
},
"node_modules/@babel/plugin-transform-private-property-in-object": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.5.tgz",
- "integrity": "sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ==",
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.3.tgz",
+ "integrity": "sha512-a5m2oLNFyje2e/rGKjVfAELTVI5mbA0FeZpBnkOWWV7eSmKQ+T/XW0Vf+29ScLzSxX+rnsarvU0oie/4m6hkxA==",
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5",
- "@babel/helper-create-class-features-plugin": "^7.22.5",
+ "@babel/helper-create-class-features-plugin": "^7.22.15",
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-private-property-in-object": "^7.14.5"
},
@@ -1999,10 +2000,11 @@
}
},
"node_modules/@babel/plugin-transform-react-display-name": {
- "version": "7.18.6",
- "license": "MIT",
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.23.3.tgz",
+ "integrity": "sha512-GnvhtVfA2OAtzdX58FJxU19rhoGeQzyVndw3GgtdECQvQFXPEZIOVULHVZGAYmOgmqjXpVpfocAbSjh99V/Fqw==",
"dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6"
+ "@babel/helper-plugin-utils": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
@@ -2012,14 +2014,15 @@
}
},
"node_modules/@babel/plugin-transform-react-jsx": {
- "version": "7.18.10",
- "license": "MIT",
+ "version": "7.23.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz",
+ "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==",
"dependencies": {
- "@babel/helper-annotate-as-pure": "^7.18.6",
- "@babel/helper-module-imports": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.9",
- "@babel/plugin-syntax-jsx": "^7.18.6",
- "@babel/types": "^7.18.10"
+ "@babel/helper-annotate-as-pure": "^7.22.5",
+ "@babel/helper-module-imports": "^7.22.15",
+ "@babel/helper-plugin-utils": "^7.22.5",
+ "@babel/plugin-syntax-jsx": "^7.23.3",
+ "@babel/types": "^7.23.4"
},
"engines": {
"node": ">=6.9.0"
@@ -2029,11 +2032,11 @@
}
},
"node_modules/@babel/plugin-transform-react-jsx-development": {
- "version": "7.18.6",
- "dev": true,
- "license": "MIT",
+ "version": "7.22.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz",
+ "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==",
"dependencies": {
- "@babel/plugin-transform-react-jsx": "^7.18.6"
+ "@babel/plugin-transform-react-jsx": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
@@ -2069,12 +2072,12 @@
}
},
"node_modules/@babel/plugin-transform-react-pure-annotations": {
- "version": "7.18.6",
- "dev": true,
- "license": "MIT",
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.23.3.tgz",
+ "integrity": "sha512-qMFdSS+TUhB7Q/3HVPnEdYJDQIk57jkntAwSuz9xfSE4n+3I+vHYCli3HoHawN1Z3RfCz/y1zXA/JXjG6cVImQ==",
"dependencies": {
- "@babel/helper-annotate-as-pure": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.6"
+ "@babel/helper-annotate-as-pure": "^7.22.5",
+ "@babel/helper-plugin-utils": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
@@ -2478,16 +2481,16 @@
}
},
"node_modules/@babel/preset-react": {
- "version": "7.18.6",
- "dev": true,
- "license": "MIT",
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.23.3.tgz",
+ "integrity": "sha512-tbkHOS9axH6Ysf2OUEqoSZ6T3Fa2SrNH6WTWSPBboxKzdxNc9qOICeLXkNG0ZEwbQ1HY8liwOce4aN/Ceyuq6w==",
"dependencies": {
- "@babel/helper-plugin-utils": "^7.18.6",
- "@babel/helper-validator-option": "^7.18.6",
- "@babel/plugin-transform-react-display-name": "^7.18.6",
- "@babel/plugin-transform-react-jsx": "^7.18.6",
- "@babel/plugin-transform-react-jsx-development": "^7.18.6",
- "@babel/plugin-transform-react-pure-annotations": "^7.18.6"
+ "@babel/helper-plugin-utils": "^7.22.5",
+ "@babel/helper-validator-option": "^7.22.15",
+ "@babel/plugin-transform-react-display-name": "^7.23.3",
+ "@babel/plugin-transform-react-jsx": "^7.22.15",
+ "@babel/plugin-transform-react-jsx-development": "^7.22.5",
+ "@babel/plugin-transform-react-pure-annotations": "^7.23.3"
},
"engines": {
"node": ">=6.9.0"
@@ -2586,11 +2589,11 @@
}
},
"node_modules/@babel/types": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
- "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
+ "version": "7.23.6",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz",
+ "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==",
"dependencies": {
- "@babel/helper-string-parser": "^7.22.5",
+ "@babel/helper-string-parser": "^7.23.4",
"@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
},
@@ -3361,53 +3364,62 @@
}
},
"node_modules/@expo/cli": {
- "version": "0.10.16",
- "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-0.10.16.tgz",
- "integrity": "sha512-EwgnRN5AMElg0JJjFLJTPk5hYkVXxnNMLIvZBiTfGoCq+rDw6u7Mg5l2Bbm/geSHOoplaHyPZ/Wr23FAuZWehA==",
+ "version": "0.16.5",
+ "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-0.16.5.tgz",
+ "integrity": "sha512-4SAAymmV97OeskbYbpiJ/HFSUHLIyYmP8RlZE0svH+A1Z2lsAbjm8G7t5dFt5WPZGHWuj0y/DzIT8eElqvwHEg==",
"dependencies": {
"@babel/runtime": "^7.20.0",
"@expo/code-signing-certificates": "0.0.5",
- "@expo/config": "~8.1.0",
- "@expo/config-plugins": "~7.2.0",
- "@expo/dev-server": "0.5.5",
+ "@expo/config": "~8.5.0",
+ "@expo/config-plugins": "~7.8.0",
"@expo/devcert": "^1.0.0",
- "@expo/env": "0.0.5",
+ "@expo/env": "~0.2.0",
+ "@expo/image-utils": "^0.4.0",
"@expo/json-file": "^8.2.37",
- "@expo/metro-config": "~0.10.0",
+ "@expo/metro-config": "~0.17.0",
"@expo/osascript": "^2.0.31",
- "@expo/package-manager": "~1.1.0",
- "@expo/plist": "^0.0.20",
- "@expo/prebuild-config": "6.2.6",
+ "@expo/package-manager": "^1.1.1",
+ "@expo/plist": "^0.1.0",
+ "@expo/prebuild-config": "6.7.2",
"@expo/rudder-sdk-node": "1.1.1",
+ "@expo/server": "^0.3.0",
"@expo/spawn-async": "1.5.0",
- "@expo/xcpretty": "^4.2.1",
+ "@expo/xcpretty": "^4.3.0",
+ "@react-native/dev-middleware": "^0.73.6",
"@urql/core": "2.3.6",
"@urql/exchange-retry": "0.3.0",
"accepts": "^1.3.8",
- "arg": "4.1.0",
+ "arg": "5.0.2",
"better-opn": "~3.0.2",
"bplist-parser": "^0.3.1",
"cacache": "^15.3.0",
"chalk": "^4.0.0",
"ci-info": "^3.3.0",
+ "connect": "^3.7.0",
"debug": "^4.3.4",
"env-editor": "^0.4.1",
+ "find-yarn-workspace-root": "~2.0.0",
"form-data": "^3.0.1",
"freeport-async": "2.0.0",
"fs-extra": "~8.1.0",
"getenv": "^1.0.0",
+ "glob": "^7.1.7",
"graphql": "15.8.0",
"graphql-tag": "^2.10.1",
"https-proxy-agent": "^5.0.1",
"internal-ip": "4.3.0",
+ "is-docker": "^2.0.0",
+ "is-wsl": "^2.1.1",
"js-yaml": "^3.13.1",
"json-schema-deref-sync": "^0.13.0",
- "md5-file": "^3.2.3",
+ "lodash.debounce": "^4.0.8",
"md5hex": "^1.0.0",
- "minipass": "3.1.6",
+ "minimatch": "^3.0.4",
+ "minipass": "3.3.6",
"node-fetch": "^2.6.7",
"node-forge": "^1.3.1",
"npm-package-arg": "^7.0.0",
+ "open": "^8.3.0",
"ora": "3.4.0",
"pretty-bytes": "5.6.0",
"progress": "2.0.3",
@@ -3415,12 +3427,15 @@
"qrcode-terminal": "0.11.0",
"require-from-string": "^2.0.2",
"requireg": "^0.2.2",
+ "resolve": "^1.22.2",
"resolve-from": "^5.0.0",
+ "resolve.exports": "^2.0.2",
"semver": "^7.5.3",
"send": "^0.18.0",
"slugify": "^1.3.4",
"structured-headers": "^0.4.1",
"tar": "^6.0.5",
+ "temp-dir": "^2.0.0",
"tempy": "^0.7.1",
"terminal-link": "^2.1.1",
"text-table": "^0.2.0",
@@ -3441,13 +3456,14 @@
}
},
"node_modules/@expo/cli/node_modules/@expo/config-plugins": {
- "version": "7.2.5",
- "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.2.5.tgz",
- "integrity": "sha512-w+5ccu1IxBHgyQk9CPFKLZOk8yZQEyTjbJwOzESK1eR7QwosbcsLkN1c1WWUZYiCXwORu3UTwJYll4+X2xxJhQ==",
- "dependencies": {
- "@expo/config-types": "^49.0.0-alpha.1",
- "@expo/json-file": "~8.2.37",
- "@expo/plist": "^0.0.20",
+ "version": "7.8.2",
+ "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.8.2.tgz",
+ "integrity": "sha512-XM2eXA5EvcpmXFCui48+bVy8GTskYSjPf2yC+LliYv8PDcedu7+pdgmbnvH4eZCyHfTMO8/UiF+w8e5WgOEj5A==",
+ "dependencies": {
+ "@expo/config-types": "^50.0.0-alpha.1",
+ "@expo/fingerprint": "^0.6.0",
+ "@expo/json-file": "~8.3.0",
+ "@expo/plist": "^0.1.0",
"@expo/sdk-runtime-versions": "^1.0.0",
"@react-native/normalize-color": "^2.0.0",
"chalk": "^4.1.2",
@@ -3458,19 +3474,39 @@
"resolve-from": "^5.0.0",
"semver": "^7.5.3",
"slash": "^3.0.0",
+ "slugify": "^1.6.6",
"xcode": "^3.0.1",
"xml2js": "0.6.0"
}
},
+ "node_modules/@expo/cli/node_modules/@expo/config-plugins/node_modules/glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/@expo/cli/node_modules/@expo/config-types": {
- "version": "49.0.0",
- "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-49.0.0.tgz",
- "integrity": "sha512-8eyREVi+K2acnMBe/rTIu1dOfyR2+AMnTLHlut+YpMV9OZPdeKV0Bs9BxAewGqBA2slslbQ9N39IS2CuTKpXkA=="
+ "version": "50.0.0",
+ "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-50.0.0.tgz",
+ "integrity": "sha512-0kkhIwXRT6EdFDwn+zTg9R2MZIAEYGn1MVkyRohAd+C9cXOb5RA8WLQi7vuxKF9m1SMtNAUrf0pO+ENK0+/KSw=="
},
"node_modules/@expo/cli/node_modules/@expo/json-file": {
- "version": "8.2.37",
- "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.2.37.tgz",
- "integrity": "sha512-YaH6rVg11JoTS2P6LsW7ybS2CULjf40AbnAHw2F1eDPuheprNjARZMnyHFPkKv7GuxCy+B9GPcbOKgc4cgA80Q==",
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.3.0.tgz",
+ "integrity": "sha512-yROUeXJXR5goagB8c3muFLCzLmdGOvoPpR5yDNaXrnTp4euNykr9yW0wWhJx4YVRTNOPtGBnEbbJBW+a9q+S6g==",
"dependencies": {
"@babel/code-frame": "~7.10.4",
"json5": "^2.2.2",
@@ -3478,9 +3514,9 @@
}
},
"node_modules/@expo/cli/node_modules/@expo/plist": {
- "version": "0.0.20",
- "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.0.20.tgz",
- "integrity": "sha512-UXQ4LXCfTZ580LDHGJ5q62jSTwJFFJ1GqBu8duQMThiHKWbMJ+gajJh6rsB6EJ3aLUr9wcauxneL5LVRFxwBEA==",
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.1.0.tgz",
+ "integrity": "sha512-xWD+8vIFif0wKyuqe3fmnmnSouXYucciZXFzS0ZD5OV9eSAS1RGQI5FaGGJ6zxJ4mpdy/4QzbLdBjnYE5vxA0g==",
"dependencies": {
"@xmldom/xmldom": "~0.7.7",
"base64-js": "^1.2.3",
@@ -3502,9 +3538,9 @@
}
},
"node_modules/@expo/cli/node_modules/arg": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz",
- "integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg=="
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
+ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
},
"node_modules/@expo/cli/node_modules/better-opn": {
"version": "3.0.2",
@@ -3591,6 +3627,25 @@
"node": ">=6 <7 || >=8"
}
},
+ "node_modules/@expo/cli/node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/@expo/cli/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -3682,17 +3737,6 @@
"node": ">=4"
}
},
- "node_modules/@expo/cli/node_modules/minipass": {
- "version": "3.1.6",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz",
- "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==",
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/@expo/cli/node_modules/onetime": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
@@ -3848,13 +3892,13 @@
}
},
"node_modules/@expo/config": {
- "version": "8.1.2",
- "resolved": "https://registry.npmjs.org/@expo/config/-/config-8.1.2.tgz",
- "integrity": "sha512-4e7hzPj50mQIlsrzOH6XZ36O094mPfPTIDIH4yv49bWNMc7GFLTofB/lcT+QyxiLaJuC0Wlk9yOLB8DIqmtwug==",
+ "version": "8.5.2",
+ "resolved": "https://registry.npmjs.org/@expo/config/-/config-8.5.2.tgz",
+ "integrity": "sha512-UYy9kWxjQAEDwlX7gwLk0+8IxGPcHJMLnYRYtR5C5xGIV+ML7tCA+qFz1p4gHZRPkJD+k7iZyqBtyqt8xm+zXw==",
"dependencies": {
"@babel/code-frame": "~7.10.4",
- "@expo/config-plugins": "~7.2.0",
- "@expo/config-types": "^49.0.0-alpha.1",
+ "@expo/config-plugins": "~7.8.2",
+ "@expo/config-types": "^50.0.0",
"@expo/json-file": "^8.2.37",
"getenv": "^1.0.0",
"glob": "7.1.6",
@@ -3973,13 +4017,14 @@
}
},
"node_modules/@expo/config/node_modules/@expo/config-plugins": {
- "version": "7.2.5",
- "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.2.5.tgz",
- "integrity": "sha512-w+5ccu1IxBHgyQk9CPFKLZOk8yZQEyTjbJwOzESK1eR7QwosbcsLkN1c1WWUZYiCXwORu3UTwJYll4+X2xxJhQ==",
- "dependencies": {
- "@expo/config-types": "^49.0.0-alpha.1",
- "@expo/json-file": "~8.2.37",
- "@expo/plist": "^0.0.20",
+ "version": "7.8.2",
+ "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.8.2.tgz",
+ "integrity": "sha512-XM2eXA5EvcpmXFCui48+bVy8GTskYSjPf2yC+LliYv8PDcedu7+pdgmbnvH4eZCyHfTMO8/UiF+w8e5WgOEj5A==",
+ "dependencies": {
+ "@expo/config-types": "^50.0.0-alpha.1",
+ "@expo/fingerprint": "^0.6.0",
+ "@expo/json-file": "~8.3.0",
+ "@expo/plist": "^0.1.0",
"@expo/sdk-runtime-versions": "^1.0.0",
"@react-native/normalize-color": "^2.0.0",
"chalk": "^4.1.2",
@@ -3990,19 +4035,20 @@
"resolve-from": "^5.0.0",
"semver": "^7.5.3",
"slash": "^3.0.0",
+ "slugify": "^1.6.6",
"xcode": "^3.0.1",
"xml2js": "0.6.0"
}
},
"node_modules/@expo/config/node_modules/@expo/config-types": {
- "version": "49.0.0",
- "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-49.0.0.tgz",
- "integrity": "sha512-8eyREVi+K2acnMBe/rTIu1dOfyR2+AMnTLHlut+YpMV9OZPdeKV0Bs9BxAewGqBA2slslbQ9N39IS2CuTKpXkA=="
+ "version": "50.0.0",
+ "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-50.0.0.tgz",
+ "integrity": "sha512-0kkhIwXRT6EdFDwn+zTg9R2MZIAEYGn1MVkyRohAd+C9cXOb5RA8WLQi7vuxKF9m1SMtNAUrf0pO+ENK0+/KSw=="
},
"node_modules/@expo/config/node_modules/@expo/json-file": {
- "version": "8.2.37",
- "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.2.37.tgz",
- "integrity": "sha512-YaH6rVg11JoTS2P6LsW7ybS2CULjf40AbnAHw2F1eDPuheprNjARZMnyHFPkKv7GuxCy+B9GPcbOKgc4cgA80Q==",
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.3.0.tgz",
+ "integrity": "sha512-yROUeXJXR5goagB8c3muFLCzLmdGOvoPpR5yDNaXrnTp4euNykr9yW0wWhJx4YVRTNOPtGBnEbbJBW+a9q+S6g==",
"dependencies": {
"@babel/code-frame": "~7.10.4",
"json5": "^2.2.2",
@@ -4010,9 +4056,9 @@
}
},
"node_modules/@expo/config/node_modules/@expo/plist": {
- "version": "0.0.20",
- "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.0.20.tgz",
- "integrity": "sha512-UXQ4LXCfTZ580LDHGJ5q62jSTwJFFJ1GqBu8duQMThiHKWbMJ+gajJh6rsB6EJ3aLUr9wcauxneL5LVRFxwBEA==",
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.1.0.tgz",
+ "integrity": "sha512-xWD+8vIFif0wKyuqe3fmnmnSouXYucciZXFzS0ZD5OV9eSAS1RGQI5FaGGJ6zxJ4mpdy/4QzbLdBjnYE5vxA0g==",
"dependencies": {
"@xmldom/xmldom": "~0.7.7",
"base64-js": "^1.2.3",
@@ -4117,222 +4163,6 @@
"node": ">=4.0"
}
},
- "node_modules/@expo/dev-server": {
- "version": "0.5.5",
- "resolved": "https://registry.npmjs.org/@expo/dev-server/-/dev-server-0.5.5.tgz",
- "integrity": "sha512-t0fT8xH1exwYsH5hh7bAt85VF+gXxg24qrbny2rR/iKoPTWFCd2JNQV8pvfLg51hvrywQ3YCBuT3lU1w7aZxFA==",
- "dependencies": {
- "@expo/bunyan": "4.0.0",
- "@expo/metro-config": "~0.10.0",
- "@expo/osascript": "2.0.33",
- "@expo/spawn-async": "^1.5.0",
- "body-parser": "^1.20.1",
- "chalk": "^4.0.0",
- "connect": "^3.7.0",
- "fs-extra": "9.0.0",
- "is-docker": "^2.0.0",
- "is-wsl": "^2.1.1",
- "node-fetch": "^2.6.0",
- "open": "^8.3.0",
- "resolve-from": "^5.0.0",
- "serialize-error": "6.0.0",
- "temp-dir": "^2.0.0"
- }
- },
- "node_modules/@expo/dev-server/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/@expo/dev-server/node_modules/body-parser": {
- "version": "1.20.2",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
- "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
- "dependencies": {
- "bytes": "3.1.2",
- "content-type": "~1.0.5",
- "debug": "2.6.9",
- "depd": "2.0.0",
- "destroy": "1.2.0",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "on-finished": "2.4.1",
- "qs": "6.11.0",
- "raw-body": "2.5.2",
- "type-is": "~1.6.18",
- "unpipe": "1.0.0"
- },
- "engines": {
- "node": ">= 0.8",
- "npm": "1.2.8000 || >= 1.4.16"
- }
- },
- "node_modules/@expo/dev-server/node_modules/bytes": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
- "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/@expo/dev-server/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/@expo/dev-server/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/@expo/dev-server/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
- },
- "node_modules/@expo/dev-server/node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dependencies": {
- "ms": "2.0.0"
- }
- },
- "node_modules/@expo/dev-server/node_modules/fs-extra": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz",
- "integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==",
- "dependencies": {
- "at-least-node": "^1.0.0",
- "graceful-fs": "^4.2.0",
- "jsonfile": "^6.0.1",
- "universalify": "^1.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@expo/dev-server/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@expo/dev-server/node_modules/iconv-lite": {
- "version": "0.4.24",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
- "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
- "dependencies": {
- "safer-buffer": ">= 2.1.2 < 3"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/@expo/dev-server/node_modules/ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
- },
- "node_modules/@expo/dev-server/node_modules/qs": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
- "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
- "dependencies": {
- "side-channel": "^1.0.4"
- },
- "engines": {
- "node": ">=0.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/@expo/dev-server/node_modules/raw-body": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
- "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
- "dependencies": {
- "bytes": "3.1.2",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "unpipe": "1.0.0"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/@expo/dev-server/node_modules/serialize-error": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-6.0.0.tgz",
- "integrity": "sha512-3vmBkMZLQO+BR4RPHcyRGdE09XCF6cvxzk2N2qn8Er3F91cy8Qt7VvEbZBOpaL53qsBbe2cFOefU6tRY6WDelA==",
- "dependencies": {
- "type-fest": "^0.12.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/@expo/dev-server/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@expo/dev-server/node_modules/type-fest": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.12.0.tgz",
- "integrity": "sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/@expo/dev-server/node_modules/universalify": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
- "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==",
- "engines": {
- "node": ">= 10.0.0"
- }
- },
"node_modules/@expo/devcert": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@expo/devcert/-/devcert-1.1.0.tgz",
@@ -4400,9 +4230,9 @@
}
},
"node_modules/@expo/env": {
- "version": "0.0.5",
- "resolved": "https://registry.npmjs.org/@expo/env/-/env-0.0.5.tgz",
- "integrity": "sha512-UXuKAqyXfhMQC3gP0OyjXmFX08Z1fkVWiGBN7bYzfoX8LHatjeHrDtI6w5nDvd8XPxPvmqaZoEDw1lW3+dz3oQ==",
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/@expo/env/-/env-0.2.1.tgz",
+ "integrity": "sha512-deZmRS7Dvp18VM8s559dq/ZjPlV1D9vtLoLXwHmCK/JYOvtNptdKsfxcWjI7ewmo6ln2PqgNI9HRI74q6Wk2eA==",
"dependencies": {
"chalk": "^4.0.0",
"debug": "^4.3.4",
@@ -4491,17 +4321,97 @@
"node": ">=8"
}
},
+ "node_modules/@expo/fingerprint": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.6.0.tgz",
+ "integrity": "sha512-KfpoVRTMwMNJ/Cf5o+Ou8M/Y0EGSTqK+rbi70M2Y0K2qgWNfMJ1gm6sYO9uc8lcTr7YSYM1Rme3dk7QXhpScNA==",
+ "dependencies": {
+ "@expo/spawn-async": "^1.5.0",
+ "chalk": "^4.1.2",
+ "debug": "^4.3.4",
+ "find-up": "^5.0.0",
+ "minimatch": "^3.0.4",
+ "p-limit": "^3.1.0",
+ "resolve-from": "^5.0.0"
+ },
+ "bin": {
+ "fingerprint": "bin/cli.js"
+ }
+ },
+ "node_modules/@expo/fingerprint/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/@expo/fingerprint/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/@expo/fingerprint/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/@expo/fingerprint/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ },
+ "node_modules/@expo/fingerprint/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@expo/fingerprint/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/@expo/image-utils": {
- "version": "0.3.22",
- "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.3.22.tgz",
- "integrity": "sha512-uzq+RERAtkWypOFOLssFnXXqEqKjNj9eXN7e97d/EXUAojNcLDoXc0sL+F5B1I4qtlsnhX01kcpoIBBZD8wZNQ==",
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.4.1.tgz",
+ "integrity": "sha512-EZb+VHSmw+a5s2hS9qksTcWylY0FDaIAVufcxoaRS9tHIXLjW5zcKW7Rhj9dSEbZbRVy9yXXdHKa3GQdUQIOFw==",
"dependencies": {
"@expo/spawn-async": "1.5.0",
"chalk": "^4.0.0",
"fs-extra": "9.0.0",
"getenv": "^1.0.0",
"jimp-compact": "0.16.1",
- "mime": "^2.4.4",
"node-fetch": "^2.6.0",
"parse-png": "^2.1.0",
"resolve-from": "^5.0.0",
@@ -4686,22 +4596,33 @@
}
},
"node_modules/@expo/metro-config": {
- "version": "0.10.7",
- "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-0.10.7.tgz",
- "integrity": "sha512-uACymEiyX0447hI4unt+2cemLQkTZXKvTev936NhtsgVnql45EP0V0pzmo/0H0WlHaAGXgvOBZJl8wFqcJ3CbQ==",
+ "version": "0.17.1",
+ "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-0.17.1.tgz",
+ "integrity": "sha512-ZOE0Jx0YTZyPpsGiiE09orGEFgZ5sMrOOFSgOe8zrns925g/uCuEbowyNq38IfQt//3xSl5mW3z0l4rxgi7hHQ==",
"dependencies": {
- "@expo/config": "~8.1.0",
- "@expo/env": "0.0.5",
- "@expo/json-file": "~8.2.37",
+ "@babel/core": "^7.20.0",
+ "@babel/generator": "^7.20.5",
+ "@babel/parser": "^7.20.0",
+ "@babel/types": "^7.20.0",
+ "@expo/config": "~8.5.0",
+ "@expo/env": "~0.2.0",
+ "@expo/json-file": "~8.3.0",
+ "@expo/spawn-async": "^1.7.2",
+ "babel-preset-fbjs": "^3.4.0",
"chalk": "^4.1.0",
"debug": "^4.3.2",
"find-yarn-workspace-root": "~2.0.0",
+ "fs-extra": "^9.1.0",
"getenv": "^1.0.0",
+ "glob": "^7.2.3",
"jsc-safe-url": "^0.2.4",
"lightningcss": "~1.19.0",
"postcss": "~8.4.21",
"resolve-from": "^5.0.0",
"sucrase": "^3.20.0"
+ },
+ "peerDependencies": {
+ "@react-native/babel-preset": "*"
}
},
"node_modules/@expo/metro-config/node_modules/@babel/code-frame": {
@@ -4713,15 +4634,26 @@
}
},
"node_modules/@expo/metro-config/node_modules/@expo/json-file": {
- "version": "8.2.37",
- "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.2.37.tgz",
- "integrity": "sha512-YaH6rVg11JoTS2P6LsW7ybS2CULjf40AbnAHw2F1eDPuheprNjARZMnyHFPkKv7GuxCy+B9GPcbOKgc4cgA80Q==",
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.3.0.tgz",
+ "integrity": "sha512-yROUeXJXR5goagB8c3muFLCzLmdGOvoPpR5yDNaXrnTp4euNykr9yW0wWhJx4YVRTNOPtGBnEbbJBW+a9q+S6g==",
"dependencies": {
"@babel/code-frame": "~7.10.4",
"json5": "^2.2.2",
"write-file-atomic": "^2.3.0"
}
},
+ "node_modules/@expo/metro-config/node_modules/@expo/spawn-async": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.7.2.tgz",
+ "integrity": "sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew==",
+ "dependencies": {
+ "cross-spawn": "^7.0.3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/@expo/metro-config/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@@ -4767,6 +4699,25 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
+ "node_modules/@expo/metro-config/node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/@expo/metro-config/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -4781,9 +4732,9 @@
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
},
"node_modules/@expo/metro-config/node_modules/postcss": {
- "version": "8.4.30",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.30.tgz",
- "integrity": "sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==",
+ "version": "8.4.32",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz",
+ "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==",
"funding": [
{
"type": "opencollective",
@@ -4799,7 +4750,7 @@
}
],
"dependencies": {
- "nanoid": "^3.3.6",
+ "nanoid": "^3.3.7",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
@@ -4955,14 +4906,14 @@
}
},
"node_modules/@expo/prebuild-config": {
- "version": "6.2.6",
- "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-6.2.6.tgz",
- "integrity": "sha512-uFVvDAm9dPg9p1qpnr4CVnpo2hmkZIL5FQz+VlIdXXJpe7ySh/qTGHtKWY/lWUshQkAJ0nwbKGPztGWdABns/Q==",
- "dependencies": {
- "@expo/config": "~8.1.0",
- "@expo/config-plugins": "~7.2.0",
- "@expo/config-types": "^49.0.0-alpha.1",
- "@expo/image-utils": "0.3.22",
+ "version": "6.7.2",
+ "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-6.7.2.tgz",
+ "integrity": "sha512-Z1GyWfl923wU29YQg6Xik4URls4qcIddWA4vLhW6mUgiRhC3HCf1keHEzK5AtWsrga4bH/H+usAY0OltgABW1w==",
+ "dependencies": {
+ "@expo/config": "~8.5.0",
+ "@expo/config-plugins": "~7.8.0",
+ "@expo/config-types": "^50.0.0-alpha.1",
+ "@expo/image-utils": "^0.4.0",
"@expo/json-file": "^8.2.37",
"debug": "^4.3.1",
"fs-extra": "^9.0.0",
@@ -4983,13 +4934,14 @@
}
},
"node_modules/@expo/prebuild-config/node_modules/@expo/config-plugins": {
- "version": "7.2.5",
- "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.2.5.tgz",
- "integrity": "sha512-w+5ccu1IxBHgyQk9CPFKLZOk8yZQEyTjbJwOzESK1eR7QwosbcsLkN1c1WWUZYiCXwORu3UTwJYll4+X2xxJhQ==",
- "dependencies": {
- "@expo/config-types": "^49.0.0-alpha.1",
- "@expo/json-file": "~8.2.37",
- "@expo/plist": "^0.0.20",
+ "version": "7.8.2",
+ "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.8.2.tgz",
+ "integrity": "sha512-XM2eXA5EvcpmXFCui48+bVy8GTskYSjPf2yC+LliYv8PDcedu7+pdgmbnvH4eZCyHfTMO8/UiF+w8e5WgOEj5A==",
+ "dependencies": {
+ "@expo/config-types": "^50.0.0-alpha.1",
+ "@expo/fingerprint": "^0.6.0",
+ "@expo/json-file": "~8.3.0",
+ "@expo/plist": "^0.1.0",
"@expo/sdk-runtime-versions": "^1.0.0",
"@react-native/normalize-color": "^2.0.0",
"chalk": "^4.1.2",
@@ -5000,19 +4952,20 @@
"resolve-from": "^5.0.0",
"semver": "^7.5.3",
"slash": "^3.0.0",
+ "slugify": "^1.6.6",
"xcode": "^3.0.1",
"xml2js": "0.6.0"
}
},
"node_modules/@expo/prebuild-config/node_modules/@expo/config-types": {
- "version": "49.0.0",
- "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-49.0.0.tgz",
- "integrity": "sha512-8eyREVi+K2acnMBe/rTIu1dOfyR2+AMnTLHlut+YpMV9OZPdeKV0Bs9BxAewGqBA2slslbQ9N39IS2CuTKpXkA=="
+ "version": "50.0.0",
+ "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-50.0.0.tgz",
+ "integrity": "sha512-0kkhIwXRT6EdFDwn+zTg9R2MZIAEYGn1MVkyRohAd+C9cXOb5RA8WLQi7vuxKF9m1SMtNAUrf0pO+ENK0+/KSw=="
},
"node_modules/@expo/prebuild-config/node_modules/@expo/json-file": {
- "version": "8.2.37",
- "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.2.37.tgz",
- "integrity": "sha512-YaH6rVg11JoTS2P6LsW7ybS2CULjf40AbnAHw2F1eDPuheprNjARZMnyHFPkKv7GuxCy+B9GPcbOKgc4cgA80Q==",
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.3.0.tgz",
+ "integrity": "sha512-yROUeXJXR5goagB8c3muFLCzLmdGOvoPpR5yDNaXrnTp4euNykr9yW0wWhJx4YVRTNOPtGBnEbbJBW+a9q+S6g==",
"dependencies": {
"@babel/code-frame": "~7.10.4",
"json5": "^2.2.2",
@@ -5020,9 +4973,9 @@
}
},
"node_modules/@expo/prebuild-config/node_modules/@expo/plist": {
- "version": "0.0.20",
- "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.0.20.tgz",
- "integrity": "sha512-UXQ4LXCfTZ580LDHGJ5q62jSTwJFFJ1GqBu8duQMThiHKWbMJ+gajJh6rsB6EJ3aLUr9wcauxneL5LVRFxwBEA==",
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.1.0.tgz",
+ "integrity": "sha512-xWD+8vIFif0wKyuqe3fmnmnSouXYucciZXFzS0ZD5OV9eSAS1RGQI5FaGGJ6zxJ4mpdy/4QzbLdBjnYE5vxA0g==",
"dependencies": {
"@xmldom/xmldom": "~0.7.7",
"base64-js": "^1.2.3",
@@ -5155,6 +5108,17 @@
"integrity": "sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ==",
"license": "MIT"
},
+ "node_modules/@expo/server": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@expo/server/-/server-0.3.0.tgz",
+ "integrity": "sha512-5oIqedpLVMnf1LGI9Xd5OOGmK3DjgH9VpuqVN4e/6DwLT05RZJMyI7ylfG6QSy1e44yOgjv242tLyg0e/zdZ+A==",
+ "dependencies": {
+ "@remix-run/node": "^1.19.3",
+ "abort-controller": "^3.0.0",
+ "debug": "^4.3.4",
+ "source-map-support": "~0.5.21"
+ }
+ },
"node_modules/@expo/spawn-async": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.5.0.tgz",
@@ -5233,9 +5197,9 @@
"integrity": "sha512-TI+l71+5aSKnShYclFa14Kum+hQMZ86b95SH6tQUG3qZEmLTarvWpKwqtTwQKqvlJSJrpFiSFu3eCuZokY6zWA=="
},
"node_modules/@expo/xcpretty": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@expo/xcpretty/-/xcpretty-4.2.2.tgz",
- "integrity": "sha512-Lke/geldJqUV0Dfxg5/QIOugOzdqZ/rQ9yHKSgGbjZtG1uiSqWyFwWvXmrdd3/sIdX33eykGvIcf+OrvvcXVUw==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@expo/xcpretty/-/xcpretty-4.3.0.tgz",
+ "integrity": "sha512-whBbvHZ2Q10T5TNmN0z5NbO6C9ZDw+XUTu8h6vVMnMzQrbGexc9oaCCZfz+L3Q7TEL5vfr+9L86nY62c3Bsm+g==",
"dependencies": {
"@babel/code-frame": "7.10.4",
"chalk": "^4.1.0",
@@ -5540,7 +5504,6 @@
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
- "dev": true,
"dependencies": {
"string-width": "^5.1.2",
"string-width-cjs": "npm:string-width@^4.2.0",
@@ -5557,7 +5520,6 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
- "dev": true,
"engines": {
"node": ">=12"
},
@@ -5569,7 +5531,6 @@
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
- "dev": true,
"engines": {
"node": ">=12"
},
@@ -5580,14 +5541,12 @@
"node_modules/@isaacs/cliui/node_modules/emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
- "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
- "dev": true
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
},
"node_modules/@isaacs/cliui/node_modules/string-width": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
- "dev": true,
"dependencies": {
"eastasianwidth": "^0.2.0",
"emoji-regex": "^9.2.2",
@@ -5604,7 +5563,6 @@
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
- "dev": true,
"dependencies": {
"ansi-regex": "^6.0.1"
},
@@ -5619,7 +5577,6 @@
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
- "dev": true,
"dependencies": {
"ansi-styles": "^6.1.0",
"string-width": "^5.0.1",
@@ -5632,6 +5589,14 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
+ "node_modules/@isaacs/ttlcache": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz",
+ "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/@istanbuljs/load-nyc-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@@ -5976,22 +5941,22 @@
}
},
"node_modules/@jest/create-cache-key-function": {
- "version": "29.5.0",
- "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.5.0.tgz",
- "integrity": "sha512-LIDZyZgnZss7uikvBKBB/USWwG+GO8+GnwRWT+YkCGDGsqLQlhm9BC3z6+7+eMs1kUlvXQIWEzBR8Q2Pnvx6lg==",
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz",
+ "integrity": "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==",
"dependencies": {
- "@jest/types": "^29.5.0"
+ "@jest/types": "^29.6.3"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/@jest/create-cache-key-function/node_modules/@jest/types": {
- "version": "29.5.0",
- "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz",
- "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz",
+ "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
"dependencies": {
- "@jest/schemas": "^29.4.3",
+ "@jest/schemas": "^29.6.3",
"@types/istanbul-lib-coverage": "^2.0.0",
"@types/istanbul-reports": "^3.0.0",
"@types/node": "*",
@@ -6003,9 +5968,9 @@
}
},
"node_modules/@jest/create-cache-key-function/node_modules/@types/yargs": {
- "version": "17.0.24",
- "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz",
- "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==",
+ "version": "17.0.31",
+ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.31.tgz",
+ "integrity": "sha512-bocYSx4DI8TmdlvxqGpVNXOgCNR1Jj0gNPhhAY+iz1rgKDAaYrAYdFYnhDV1IFuiuVc9HkOwyDcFxaTElF3/wg==",
"dependencies": {
"@types/yargs-parser": "*"
}
@@ -6075,14 +6040,14 @@
}
},
"node_modules/@jest/environment": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.6.2.tgz",
- "integrity": "sha512-AEcW43C7huGd/vogTddNNTDRpO6vQ2zaQNrttvWV18ArBx9Z56h7BIsXkNFJVOO4/kblWEQz30ckw0+L3izc+Q==",
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz",
+ "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==",
"dependencies": {
- "@jest/fake-timers": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/fake-timers": "^29.7.0",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
- "jest-mock": "^29.6.2"
+ "jest-mock": "^29.7.0"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
@@ -6200,16 +6165,16 @@
}
},
"node_modules/@jest/fake-timers": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.6.2.tgz",
- "integrity": "sha512-euZDmIlWjm1Z0lJ1D0f7a0/y5Kh/koLFMUBE5SUYWrmy8oNhJpbTBDAP6CxKnadcMLDoDf4waRYCe35cH6G6PA==",
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz",
+ "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==",
"dependencies": {
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"@sinonjs/fake-timers": "^10.0.2",
"@types/node": "*",
- "jest-message-util": "^29.6.2",
- "jest-mock": "^29.6.2",
- "jest-util": "^29.6.2"
+ "jest-message-util": "^29.7.0",
+ "jest-mock": "^29.7.0",
+ "jest-util": "^29.7.0"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
@@ -7956,7 +7921,6 @@
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
- "dev": true,
"optional": true,
"engines": {
"node": ">=14"
@@ -8550,14 +8514,14 @@
}
},
"node_modules/@react-native-async-storage/async-storage": {
- "version": "1.19.3",
- "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.19.3.tgz",
- "integrity": "sha512-CwGfoHCWdPOTPS+2fW6YRE1fFBpT9++ahLEroX5hkgwyoQ+TkmjOaUxixdEIoVua9Pz5EF2pGOIJzqOTMWfBlA==",
+ "version": "1.21.0",
+ "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.21.0.tgz",
+ "integrity": "sha512-JL0w36KuFHFCvnbOXRekqVAUplmOyT/OuCQkogo6X98MtpSaJOKEAeZnYO8JB0U/RIEixZaGI5px73YbRm/oag==",
"dependencies": {
"merge-options": "^3.0.4"
},
"peerDependencies": {
- "react-native": "^0.0.0-0 || 0.60 - 0.72 || 1000.0.0"
+ "react-native": "^0.0.0-0 || >=0.60 <1.0"
}
},
"node_modules/@react-native-camera-roll/camera-roll": {
@@ -8579,44 +8543,44 @@
}
},
"node_modules/@react-native-community/cli": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-11.3.6.tgz",
- "integrity": "sha512-bdwOIYTBVQ9VK34dsf6t3u6vOUU5lfdhKaAxiAVArjsr7Je88Bgs4sAbsOYsNK3tkE8G77U6wLpekknXcanlww==",
- "dependencies": {
- "@react-native-community/cli-clean": "11.3.6",
- "@react-native-community/cli-config": "11.3.6",
- "@react-native-community/cli-debugger-ui": "11.3.6",
- "@react-native-community/cli-doctor": "11.3.6",
- "@react-native-community/cli-hermes": "11.3.6",
- "@react-native-community/cli-plugin-metro": "11.3.6",
- "@react-native-community/cli-server-api": "11.3.6",
- "@react-native-community/cli-tools": "11.3.6",
- "@react-native-community/cli-types": "11.3.6",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-12.3.0.tgz",
+ "integrity": "sha512-XeQohi2E+S2+MMSz97QcEZ/bWpi8sfKiQg35XuYeJkc32Til2g0b97jRpn0/+fV0BInHoG1CQYWwHA7opMsrHg==",
+ "dependencies": {
+ "@react-native-community/cli-clean": "12.3.0",
+ "@react-native-community/cli-config": "12.3.0",
+ "@react-native-community/cli-debugger-ui": "12.3.0",
+ "@react-native-community/cli-doctor": "12.3.0",
+ "@react-native-community/cli-hermes": "12.3.0",
+ "@react-native-community/cli-plugin-metro": "12.3.0",
+ "@react-native-community/cli-server-api": "12.3.0",
+ "@react-native-community/cli-tools": "12.3.0",
+ "@react-native-community/cli-types": "12.3.0",
"chalk": "^4.1.2",
"commander": "^9.4.1",
+ "deepmerge": "^4.3.0",
"execa": "^5.0.0",
"find-up": "^4.1.0",
"fs-extra": "^8.1.0",
"graceful-fs": "^4.1.3",
- "prompts": "^2.4.0",
+ "prompts": "^2.4.2",
"semver": "^7.5.2"
},
"bin": {
"react-native": "build/bin.js"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/@react-native-community/cli-clean": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-11.3.6.tgz",
- "integrity": "sha512-jOOaeG5ebSXTHweq1NznVJVAFKtTFWL4lWgUXl845bCGX7t1lL8xQNWHKwT8Oh1pGR2CI3cKmRjY4hBg+pEI9g==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-12.3.0.tgz",
+ "integrity": "sha512-iAgLCOWYRGh9ukr+eVQnhkV/OqN3V2EGd/in33Ggn/Mj4uO6+oUncXFwB+yjlyaUNz6FfjudhIz09yYGSF+9sg==",
"dependencies": {
- "@react-native-community/cli-tools": "11.3.6",
+ "@react-native-community/cli-tools": "12.3.0",
"chalk": "^4.1.2",
- "execa": "^5.0.0",
- "prompts": "^2.4.0"
+ "execa": "^5.0.0"
}
},
"node_modules/@react-native-community/cli-clean/node_modules/ansi-styles": {
@@ -8684,11 +8648,11 @@
}
},
"node_modules/@react-native-community/cli-config": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-11.3.6.tgz",
- "integrity": "sha512-edy7fwllSFLan/6BG6/rznOBCLPrjmJAE10FzkEqNLHowi0bckiAPg1+1jlgQ2qqAxV5kuk+c9eajVfQvPLYDA==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-12.3.0.tgz",
+ "integrity": "sha512-BrTn5ndFD9uOxO8kxBQ32EpbtOvAsQExGPI7SokdI4Zlve70FziLtTq91LTlTUgMq1InVZn/jJb3VIDk6BTInQ==",
"dependencies": {
- "@react-native-community/cli-tools": "11.3.6",
+ "@react-native-community/cli-tools": "12.3.0",
"chalk": "^4.1.2",
"cosmiconfig": "^5.1.0",
"deepmerge": "^4.3.0",
@@ -8807,34 +8771,33 @@
}
},
"node_modules/@react-native-community/cli-debugger-ui": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-11.3.6.tgz",
- "integrity": "sha512-jhMOSN/iOlid9jn/A2/uf7HbC3u7+lGktpeGSLnHNw21iahFBzcpuO71ekEdlmTZ4zC/WyxBXw9j2ka33T358w==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-12.3.0.tgz",
+ "integrity": "sha512-w3b0iwjQlk47GhZWHaeTG8kKH09NCMUJO729xSdMBXE8rlbm4kHpKbxQY9qKb6NlfWSJN4noGY+FkNZS2rRwnQ==",
"dependencies": {
"serve-static": "^1.13.1"
}
},
"node_modules/@react-native-community/cli-doctor": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-11.3.6.tgz",
- "integrity": "sha512-UT/Tt6omVPi1j6JEX+CObc85eVFghSZwy4GR9JFMsO7gNg2Tvcu1RGWlUkrbmWMAMHw127LUu6TGK66Ugu1NLA==",
- "dependencies": {
- "@react-native-community/cli-config": "11.3.6",
- "@react-native-community/cli-platform-android": "11.3.6",
- "@react-native-community/cli-platform-ios": "11.3.6",
- "@react-native-community/cli-tools": "11.3.6",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-12.3.0.tgz",
+ "integrity": "sha512-BPCwNNesoQMkKsxB08Ayy6URgGQ8Kndv6mMhIvJSNdST3J1+x3ehBHXzG9B9Vfi+DrTKRb8lmEl/b/7VkDlPkA==",
+ "dependencies": {
+ "@react-native-community/cli-config": "12.3.0",
+ "@react-native-community/cli-platform-android": "12.3.0",
+ "@react-native-community/cli-platform-ios": "12.3.0",
+ "@react-native-community/cli-tools": "12.3.0",
"chalk": "^4.1.2",
"command-exists": "^1.2.8",
- "envinfo": "^7.7.2",
+ "deepmerge": "^4.3.0",
+ "envinfo": "^7.10.0",
"execa": "^5.0.0",
"hermes-profile-transformer": "^0.0.6",
"ip": "^1.1.5",
"node-stream-zip": "^1.9.1",
"ora": "^5.4.1",
- "prompts": "^2.4.0",
"semver": "^7.5.2",
"strip-ansi": "^5.2.0",
- "sudo-prompt": "^9.0.0",
"wcwidth": "^1.0.1",
"yaml": "^2.2.1"
}
@@ -8920,12 +8883,12 @@
}
},
"node_modules/@react-native-community/cli-hermes": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-11.3.6.tgz",
- "integrity": "sha512-O55YAYGZ3XynpUdePPVvNuUPGPY0IJdctLAOHme73OvS80gNwfntHDXfmY70TGHWIfkK2zBhA0B+2v8s5aTyTA==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-12.3.0.tgz",
+ "integrity": "sha512-G6FxpeZBO4AimKZwtWR3dpXRqTvsmEqlIkkxgwthdzn3LbVjDVIXKpVYU9PkR5cnT+KuAUxO0WwthrJ6Nmrrlg==",
"dependencies": {
- "@react-native-community/cli-platform-android": "11.3.6",
- "@react-native-community/cli-tools": "11.3.6",
+ "@react-native-community/cli-platform-android": "12.3.0",
+ "@react-native-community/cli-tools": "12.3.0",
"chalk": "^4.1.2",
"hermes-profile-transformer": "^0.0.6",
"ip": "^1.1.5"
@@ -9001,13 +8964,14 @@
}
},
"node_modules/@react-native-community/cli-platform-android": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-11.3.6.tgz",
- "integrity": "sha512-ZARrpLv5tn3rmhZc//IuDM1LSAdYnjUmjrp58RynlvjLDI4ZEjBAGCQmgysRgXAsK7ekMrfkZgemUczfn9td2A==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-12.3.0.tgz",
+ "integrity": "sha512-VU1NZw63+GLU2TnyQ919bEMThpHQ/oMFju9MCfrd3pyPJz4Sn+vc3NfnTDUVA5Z5yfLijFOkHIHr4vo/C9bjnw==",
"dependencies": {
- "@react-native-community/cli-tools": "11.3.6",
+ "@react-native-community/cli-tools": "12.3.0",
"chalk": "^4.1.2",
"execa": "^5.0.0",
+ "fast-xml-parser": "^4.2.4",
"glob": "^7.1.3",
"logkitty": "^0.7.1"
}
@@ -9077,11 +9041,11 @@
}
},
"node_modules/@react-native-community/cli-platform-ios": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-11.3.6.tgz",
- "integrity": "sha512-tZ9VbXWiRW+F+fbZzpLMZlj93g3Q96HpuMsS6DRhrTiG+vMQ3o6oPWSEEmMGOvJSYU7+y68Dc9ms2liC7VD6cw==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-12.3.0.tgz",
+ "integrity": "sha512-H95Sgt3wT7L8V75V0syFJDtv4YgqK5zbu69ko4yrXGv8dv2EBi6qZP0VMmkqXDamoPm9/U7tDTdbcf26ctnLfg==",
"dependencies": {
- "@react-native-community/cli-tools": "11.3.6",
+ "@react-native-community/cli-tools": "12.3.0",
"chalk": "^4.1.2",
"execa": "^5.0.0",
"fast-xml-parser": "^4.0.12",
@@ -9154,696 +9118,17 @@
}
},
"node_modules/@react-native-community/cli-plugin-metro": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-11.3.6.tgz",
- "integrity": "sha512-D97racrPX3069ibyabJNKw9aJpVcaZrkYiEzsEnx50uauQtPDoQ1ELb/5c6CtMhAEGKoZ0B5MS23BbsSZcLs2g==",
- "dependencies": {
- "@react-native-community/cli-server-api": "11.3.6",
- "@react-native-community/cli-tools": "11.3.6",
- "chalk": "^4.1.2",
- "execa": "^5.0.0",
- "metro": "0.76.7",
- "metro-config": "0.76.7",
- "metro-core": "0.76.7",
- "metro-react-native-babel-transformer": "0.76.7",
- "metro-resolver": "0.76.7",
- "metro-runtime": "0.76.7",
- "readline": "^1.3.0"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/@jest/types": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz",
- "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==",
- "dependencies": {
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^16.0.0",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/@types/yargs": {
- "version": "16.0.6",
- "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.6.tgz",
- "integrity": "sha512-oTP7/Q13GSPrgcwEwdlnkoZSQ1Hg9THe644qq8PG6hhJzjZ3qj1JjEFPIwWV/IXVs5XGIVqtkNOS9kh63WIJ+A==",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/ci-info": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
- "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/cliui": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
- "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
- "dependencies": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.1",
- "wrap-ansi": "^7.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/cosmiconfig": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
- "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
- "dependencies": {
- "import-fresh": "^2.0.0",
- "is-directory": "^0.3.1",
- "js-yaml": "^3.13.1",
- "parse-json": "^4.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dependencies": {
- "ms": "2.0.0"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/import-fresh": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
- "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==",
- "dependencies": {
- "caller-path": "^2.0.0",
- "resolve-from": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/jest-regex-util": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz",
- "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==",
- "engines": {
- "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/jest-util": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz",
- "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==",
- "dependencies": {
- "@jest/types": "^27.5.1",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "ci-info": "^3.2.0",
- "graceful-fs": "^4.2.9",
- "picomatch": "^2.2.3"
- },
- "engines": {
- "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/jest-util/node_modules/ci-info": {
- "version": "3.8.0",
- "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz",
- "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/sibiraj-s"
- }
- ],
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/jest-worker": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
- "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
- "dependencies": {
- "@types/node": "*",
- "merge-stream": "^2.0.0",
- "supports-color": "^8.0.0"
- },
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/jest-worker/node_modules/supports-color": {
- "version": "8.1.1",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
- "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/supports-color?sponsor=1"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro/-/metro-0.76.7.tgz",
- "integrity": "sha512-67ZGwDeumEPnrHI+pEDSKH2cx+C81Gx8Mn5qOtmGUPm/Up9Y4I1H2dJZ5n17MWzejNo0XAvPh0QL0CrlJEODVQ==",
- "dependencies": {
- "@babel/code-frame": "^7.0.0",
- "@babel/core": "^7.20.0",
- "@babel/generator": "^7.20.0",
- "@babel/parser": "^7.20.0",
- "@babel/template": "^7.0.0",
- "@babel/traverse": "^7.20.0",
- "@babel/types": "^7.20.0",
- "accepts": "^1.3.7",
- "async": "^3.2.2",
- "chalk": "^4.0.0",
- "ci-info": "^2.0.0",
- "connect": "^3.6.5",
- "debug": "^2.2.0",
- "denodeify": "^1.2.1",
- "error-stack-parser": "^2.0.6",
- "graceful-fs": "^4.2.4",
- "hermes-parser": "0.12.0",
- "image-size": "^1.0.2",
- "invariant": "^2.2.4",
- "jest-worker": "^27.2.0",
- "jsc-safe-url": "^0.2.2",
- "lodash.throttle": "^4.1.1",
- "metro-babel-transformer": "0.76.7",
- "metro-cache": "0.76.7",
- "metro-cache-key": "0.76.7",
- "metro-config": "0.76.7",
- "metro-core": "0.76.7",
- "metro-file-map": "0.76.7",
- "metro-inspector-proxy": "0.76.7",
- "metro-minify-terser": "0.76.7",
- "metro-minify-uglify": "0.76.7",
- "metro-react-native-babel-preset": "0.76.7",
- "metro-resolver": "0.76.7",
- "metro-runtime": "0.76.7",
- "metro-source-map": "0.76.7",
- "metro-symbolicate": "0.76.7",
- "metro-transform-plugins": "0.76.7",
- "metro-transform-worker": "0.76.7",
- "mime-types": "^2.1.27",
- "node-fetch": "^2.2.0",
- "nullthrows": "^1.1.1",
- "rimraf": "^3.0.2",
- "serialize-error": "^2.1.0",
- "source-map": "^0.5.6",
- "strip-ansi": "^6.0.0",
- "throat": "^5.0.0",
- "ws": "^7.5.1",
- "yargs": "^17.6.2"
- },
- "bin": {
- "metro": "src/cli.js"
- },
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-babel-transformer": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.76.7.tgz",
- "integrity": "sha512-bgr2OFn0J4r0qoZcHrwEvccF7g9k3wdgTOgk6gmGHrtlZ1Jn3oCpklW/DfZ9PzHfjY2mQammKTc19g/EFGyOJw==",
- "dependencies": {
- "@babel/core": "^7.20.0",
- "hermes-parser": "0.12.0",
- "nullthrows": "^1.1.1"
- },
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-cache": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.76.7.tgz",
- "integrity": "sha512-nWBMztrs5RuSxZRI7hgFgob5PhYDmxICh9FF8anm9/ito0u0vpPvRxt7sRu8fyeD2AHdXqE7kX32rWY0LiXgeg==",
- "dependencies": {
- "metro-core": "0.76.7",
- "rimraf": "^3.0.2"
- },
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-cache-key": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.76.7.tgz",
- "integrity": "sha512-0pecoIzwsD/Whn/Qfa+SDMX2YyasV0ndbcgUFx7w1Ct2sLHClujdhQ4ik6mvQmsaOcnGkIyN0zcceMDjC2+BFQ==",
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-config": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.76.7.tgz",
- "integrity": "sha512-CFDyNb9bqxZemiChC/gNdXZ7OQkIwmXzkrEXivcXGbgzlt/b2juCv555GWJHyZSlorwnwJfY3uzAFu4A9iRVfg==",
- "dependencies": {
- "connect": "^3.6.5",
- "cosmiconfig": "^5.0.5",
- "jest-validate": "^29.2.1",
- "metro": "0.76.7",
- "metro-cache": "0.76.7",
- "metro-core": "0.76.7",
- "metro-runtime": "0.76.7"
- },
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-core": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.76.7.tgz",
- "integrity": "sha512-0b8KfrwPmwCMW+1V7ZQPkTy2tsEKZjYG9Pu1PTsu463Z9fxX7WaR0fcHFshv+J1CnQSUTwIGGjbNvj1teKe+pw==",
- "dependencies": {
- "lodash.throttle": "^4.1.1",
- "metro-resolver": "0.76.7"
- },
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-file-map": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.76.7.tgz",
- "integrity": "sha512-s+zEkTcJ4mOJTgEE2ht4jIo1DZfeWreQR3tpT3gDV/Y/0UQ8aJBTv62dE775z0GLsWZApiblAYZsj7ZE8P06nw==",
- "dependencies": {
- "anymatch": "^3.0.3",
- "debug": "^2.2.0",
- "fb-watchman": "^2.0.0",
- "graceful-fs": "^4.2.4",
- "invariant": "^2.2.4",
- "jest-regex-util": "^27.0.6",
- "jest-util": "^27.2.0",
- "jest-worker": "^27.2.0",
- "micromatch": "^4.0.4",
- "node-abort-controller": "^3.1.1",
- "nullthrows": "^1.1.1",
- "walker": "^1.0.7"
- },
- "engines": {
- "node": ">=16"
- },
- "optionalDependencies": {
- "fsevents": "^2.3.2"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-inspector-proxy": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.76.7.tgz",
- "integrity": "sha512-rNZ/6edTl/1qUekAhAbaFjczMphM50/UjtxiKulo6vqvgn/Mjd9hVqDvVYfAMZXqPvlusD88n38UjVYPkruLSg==",
- "dependencies": {
- "connect": "^3.6.5",
- "debug": "^2.2.0",
- "node-fetch": "^2.2.0",
- "ws": "^7.5.1",
- "yargs": "^17.6.2"
- },
- "bin": {
- "metro-inspector-proxy": "src/cli.js"
- },
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-minify-terser": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.76.7.tgz",
- "integrity": "sha512-FQiZGhIxCzhDwK4LxyPMLlq0Tsmla10X7BfNGlYFK0A5IsaVKNJbETyTzhpIwc+YFRT4GkFFwgo0V2N5vxO5HA==",
- "dependencies": {
- "terser": "^5.15.0"
- },
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-minify-uglify": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.76.7.tgz",
- "integrity": "sha512-FuXIU3j2uNcSvQtPrAJjYWHruPiQ+EpE++J9Z+VznQKEHcIxMMoQZAfIF2IpZSrZYfLOjVFyGMvj41jQMxV1Vw==",
- "dependencies": {
- "uglify-es": "^3.1.9"
- },
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-react-native-babel-preset": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.76.7.tgz",
- "integrity": "sha512-R25wq+VOSorAK3hc07NW0SmN8z9S/IR0Us0oGAsBcMZnsgkbOxu77Mduqf+f4is/wnWHc5+9bfiqdLnaMngiVw==",
- "dependencies": {
- "@babel/core": "^7.20.0",
- "@babel/plugin-proposal-async-generator-functions": "^7.0.0",
- "@babel/plugin-proposal-class-properties": "^7.18.0",
- "@babel/plugin-proposal-export-default-from": "^7.0.0",
- "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.0",
- "@babel/plugin-proposal-numeric-separator": "^7.0.0",
- "@babel/plugin-proposal-object-rest-spread": "^7.20.0",
- "@babel/plugin-proposal-optional-catch-binding": "^7.0.0",
- "@babel/plugin-proposal-optional-chaining": "^7.20.0",
- "@babel/plugin-syntax-dynamic-import": "^7.8.0",
- "@babel/plugin-syntax-export-default-from": "^7.0.0",
- "@babel/plugin-syntax-flow": "^7.18.0",
- "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0",
- "@babel/plugin-syntax-optional-chaining": "^7.0.0",
- "@babel/plugin-transform-arrow-functions": "^7.0.0",
- "@babel/plugin-transform-async-to-generator": "^7.20.0",
- "@babel/plugin-transform-block-scoping": "^7.0.0",
- "@babel/plugin-transform-classes": "^7.0.0",
- "@babel/plugin-transform-computed-properties": "^7.0.0",
- "@babel/plugin-transform-destructuring": "^7.20.0",
- "@babel/plugin-transform-flow-strip-types": "^7.20.0",
- "@babel/plugin-transform-function-name": "^7.0.0",
- "@babel/plugin-transform-literals": "^7.0.0",
- "@babel/plugin-transform-modules-commonjs": "^7.0.0",
- "@babel/plugin-transform-named-capturing-groups-regex": "^7.0.0",
- "@babel/plugin-transform-parameters": "^7.0.0",
- "@babel/plugin-transform-react-display-name": "^7.0.0",
- "@babel/plugin-transform-react-jsx": "^7.0.0",
- "@babel/plugin-transform-react-jsx-self": "^7.0.0",
- "@babel/plugin-transform-react-jsx-source": "^7.0.0",
- "@babel/plugin-transform-runtime": "^7.0.0",
- "@babel/plugin-transform-shorthand-properties": "^7.0.0",
- "@babel/plugin-transform-spread": "^7.0.0",
- "@babel/plugin-transform-sticky-regex": "^7.0.0",
- "@babel/plugin-transform-typescript": "^7.5.0",
- "@babel/plugin-transform-unicode-regex": "^7.0.0",
- "@babel/template": "^7.0.0",
- "babel-plugin-transform-flow-enums": "^0.0.2",
- "react-refresh": "^0.4.0"
- },
- "engines": {
- "node": ">=16"
- },
- "peerDependencies": {
- "@babel/core": "*"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-react-native-babel-transformer": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.76.7.tgz",
- "integrity": "sha512-W6lW3J7y/05ph3c2p3KKJNhH0IdyxdOCbQ5it7aM2MAl0SM4wgKjaV6EYv9b3rHklpV6K3qMH37UKVcjMooWiA==",
- "dependencies": {
- "@babel/core": "^7.20.0",
- "babel-preset-fbjs": "^3.4.0",
- "hermes-parser": "0.12.0",
- "metro-react-native-babel-preset": "0.76.7",
- "nullthrows": "^1.1.1"
- },
- "engines": {
- "node": ">=16"
- },
- "peerDependencies": {
- "@babel/core": "*"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-resolver": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.76.7.tgz",
- "integrity": "sha512-pC0Wgq29HHIHrwz23xxiNgylhI8Rq1V01kQaJ9Kz11zWrIdlrH0ZdnJ7GC6qA0ErROG+cXmJ0rJb8/SW1Zp2IA==",
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-runtime": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.76.7.tgz",
- "integrity": "sha512-MuWHubQHymUWBpZLwuKZQgA/qbb35WnDAKPo83rk7JRLIFPvzXSvFaC18voPuzJBt1V98lKQIonh6MiC9gd8Ug==",
- "dependencies": {
- "@babel/runtime": "^7.0.0",
- "react-refresh": "^0.4.0"
- },
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-source-map": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.76.7.tgz",
- "integrity": "sha512-Prhx7PeRV1LuogT0Kn5VjCuFu9fVD68eefntdWabrksmNY6mXK8pRqzvNJOhTojh6nek+RxBzZeD6MIOOyXS6w==",
- "dependencies": {
- "@babel/traverse": "^7.20.0",
- "@babel/types": "^7.20.0",
- "invariant": "^2.2.4",
- "metro-symbolicate": "0.76.7",
- "nullthrows": "^1.1.1",
- "ob1": "0.76.7",
- "source-map": "^0.5.6",
- "vlq": "^1.0.0"
- },
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-symbolicate": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.76.7.tgz",
- "integrity": "sha512-p0zWEME5qLSL1bJb93iq+zt5fz3sfVn9xFYzca1TJIpY5MommEaS64Va87lp56O0sfEIvh4307Oaf/ZzRjuLiQ==",
- "dependencies": {
- "invariant": "^2.2.4",
- "metro-source-map": "0.76.7",
- "nullthrows": "^1.1.1",
- "source-map": "^0.5.6",
- "through2": "^2.0.1",
- "vlq": "^1.0.0"
- },
- "bin": {
- "metro-symbolicate": "src/index.js"
- },
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-transform-plugins": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.76.7.tgz",
- "integrity": "sha512-iSmnjVApbdivjuzb88Orb0JHvcEt5veVyFAzxiS5h0QB+zV79w6JCSqZlHCrbNOkOKBED//LqtKbFVakxllnNg==",
- "dependencies": {
- "@babel/core": "^7.20.0",
- "@babel/generator": "^7.20.0",
- "@babel/template": "^7.0.0",
- "@babel/traverse": "^7.20.0",
- "nullthrows": "^1.1.1"
- },
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-transform-worker": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.76.7.tgz",
- "integrity": "sha512-cGvELqFMVk9XTC15CMVzrCzcO6sO1lURfcbgjuuPdzaWuD11eEyocvkTX0DPiRjsvgAmicz4XYxVzgYl3MykDw==",
- "dependencies": {
- "@babel/core": "^7.20.0",
- "@babel/generator": "^7.20.0",
- "@babel/parser": "^7.20.0",
- "@babel/types": "^7.20.0",
- "babel-preset-fbjs": "^3.4.0",
- "metro": "0.76.7",
- "metro-babel-transformer": "0.76.7",
- "metro-cache": "0.76.7",
- "metro-cache-key": "0.76.7",
- "metro-source-map": "0.76.7",
- "metro-transform-plugins": "0.76.7",
- "nullthrows": "^1.1.1"
- },
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/ob1": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.76.7.tgz",
- "integrity": "sha512-BQdRtxxoUNfSoZxqeBGOyuT9nEYSn18xZHwGMb0mMVpn2NBcYbnyKY4BK2LIHRgw33CBGlUmE+KMaNvyTpLLtQ==",
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/parse-json": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
- "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
- "dependencies": {
- "error-ex": "^1.3.1",
- "json-parse-better-errors": "^1.0.1"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/react-refresh": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz",
- "integrity": "sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/resolve-from": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
- "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/serialize-error": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz",
- "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/ws": {
- "version": "7.5.9",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
- "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
- "engines": {
- "node": ">=8.3.0"
- },
- "peerDependencies": {
- "bufferutil": "^4.0.1",
- "utf-8-validate": "^5.0.2"
- },
- "peerDependenciesMeta": {
- "bufferutil": {
- "optional": true
- },
- "utf-8-validate": {
- "optional": true
- }
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/y18n": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/yargs": {
- "version": "17.7.2",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
- "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
- "dependencies": {
- "cliui": "^8.0.1",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "require-directory": "^2.1.1",
- "string-width": "^4.2.3",
- "y18n": "^5.0.5",
- "yargs-parser": "^21.1.1"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@react-native-community/cli-plugin-metro/node_modules/yargs-parser": {
- "version": "21.1.1",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
- "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
- "engines": {
- "node": ">=12"
- }
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-12.3.0.tgz",
+ "integrity": "sha512-tYNHIYnNmxrBcsqbE2dAnLMzlKI3Cp1p1xUgTrNaOMsGPDN1epzNfa34n6Nps3iwKElSL7Js91CzYNqgTalucA=="
},
"node_modules/@react-native-community/cli-server-api": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-11.3.6.tgz",
- "integrity": "sha512-8GUKodPnURGtJ9JKg8yOHIRtWepPciI3ssXVw5jik7+dZ43yN8P5BqCoDaq8e1H1yRer27iiOfT7XVnwk8Dueg==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-12.3.0.tgz",
+ "integrity": "sha512-Rode8NrdyByC+lBKHHn+/W8Zu0c+DajJvLmOWbe2WY/ECvnwcd9MHHbu92hlT2EQaJ9LbLhGrSbQE3cQy9EOCw==",
"dependencies": {
- "@react-native-community/cli-debugger-ui": "11.3.6",
- "@react-native-community/cli-tools": "11.3.6",
+ "@react-native-community/cli-debugger-ui": "12.3.0",
+ "@react-native-community/cli-tools": "12.3.0",
"compression": "^1.7.1",
"connect": "^3.6.5",
"errorhandler": "^1.5.1",
@@ -9931,9 +9216,9 @@
}
},
"node_modules/@react-native-community/cli-tools": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-11.3.6.tgz",
- "integrity": "sha512-JpmUTcDwAGiTzLsfMlIAYpCMSJ9w2Qlf7PU7mZIRyEu61UzEawyw83DkqfbzDPBuRwRnaeN44JX2CP/yTO3ThQ==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-12.3.0.tgz",
+ "integrity": "sha512-2GafnCr8D88VdClwnm9KZfkEb+lzVoFdr/7ybqhdeYM0Vnt/tr2N+fM1EQzwI1DpzXiBzTYemw8GjRq+Utcz2Q==",
"dependencies": {
"appdirsjs": "^1.2.4",
"chalk": "^4.1.2",
@@ -9943,7 +9228,8 @@
"open": "^6.2.0",
"ora": "^5.4.1",
"semver": "^7.5.2",
- "shell-quote": "^1.7.3"
+ "shell-quote": "^1.7.3",
+ "sudo-prompt": "^9.0.0"
}
},
"node_modules/@react-native-community/cli-tools/node_modules/ansi-styles": {
@@ -10030,9 +9316,9 @@
}
},
"node_modules/@react-native-community/cli-types": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-11.3.6.tgz",
- "integrity": "sha512-6DxjrMKx5x68N/tCJYVYRKAtlRHbtUVBZrnAvkxbRWFD9v4vhNgsPM0RQm8i2vRugeksnao5mbnRGpS6c0awCw==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-12.3.0.tgz",
+ "integrity": "sha512-MgOkmrXH4zsGxhte4YqKL7d+N8ZNEd3w1wo56MZlhu5WabwCJh87wYpU5T8vyfujFLYOFuFK5jjlcbs8F4/WDw==",
"dependencies": {
"joi": "^17.2.1"
}
@@ -10322,8 +9608,9 @@
}
},
"node_modules/@react-native-community/netinfo": {
- "version": "9.3.10",
- "license": "MIT",
+ "version": "11.2.1",
+ "resolved": "https://registry.npmjs.org/@react-native-community/netinfo/-/netinfo-11.2.1.tgz",
+ "integrity": "sha512-n9kgmH7vLaU7Cdo8vGfJGGwhrlgppaOSq5zKj9I7H4k5iRM3aNtwURw83mgrc22Ip7nSye2afZV2xDiIyvHttQ==",
"peerDependencies": {
"react-native": ">=0.59"
}
@@ -10393,53 +9680,314 @@
}
},
"node_modules/@react-native-picker/picker": {
- "version": "2.4.4",
- "license": "MIT",
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@react-native-picker/picker/-/picker-2.5.1.tgz",
+ "integrity": "sha512-/sADUfQsosMRYtrqqL3ZYZSECRygj0fXtpRLqxJfwuMEoqfvfn40756R6B1alzusVvDRZFI0ari0iQid56hA/Q==",
"peerDependencies": {
"react": ">=16",
"react-native": ">=0.57"
}
},
"node_modules/@react-native/assets-registry": {
- "version": "0.72.0",
- "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.72.0.tgz",
- "integrity": "sha512-Im93xRJuHHxb1wniGhBMsxLwcfzdYreSZVQGDoMJgkd6+Iky61LInGEHnQCTN0fKNYF1Dvcofb4uMmE1RQHXHQ=="
+ "version": "0.73.1",
+ "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.73.1.tgz",
+ "integrity": "sha512-2FgAbU7uKM5SbbW9QptPPZx8N9Ke2L7bsHb+EhAanZjFZunA9PaYtyjUQ1s7HD+zDVqOQIvjkpXSv7Kejd2tqg==",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@react-native/babel-plugin-codegen": {
+ "version": "0.73.2",
+ "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.73.2.tgz",
+ "integrity": "sha512-PadyFZWVaWXIBP7Q5dgEL7eAd7tnsgsLjoHJB1hIRZZuVUg1Zqe3nULwC7RFAqOtr5Qx7KXChkFFcKQ3WnZzGw==",
+ "dependencies": {
+ "@react-native/codegen": "0.73.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@react-native/babel-preset": {
+ "version": "0.73.19",
+ "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.73.19.tgz",
+ "integrity": "sha512-ujon01uMOREZecIltQxPDmJ6xlVqAUFGI/JCSpeVYdxyXBoBH5dBb0ihj7h6LKH1q1jsnO9z4MxfddtypKkIbg==",
+ "dependencies": {
+ "@babel/core": "^7.20.0",
+ "@babel/plugin-proposal-async-generator-functions": "^7.0.0",
+ "@babel/plugin-proposal-class-properties": "^7.18.0",
+ "@babel/plugin-proposal-export-default-from": "^7.0.0",
+ "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.0",
+ "@babel/plugin-proposal-numeric-separator": "^7.0.0",
+ "@babel/plugin-proposal-object-rest-spread": "^7.20.0",
+ "@babel/plugin-proposal-optional-catch-binding": "^7.0.0",
+ "@babel/plugin-proposal-optional-chaining": "^7.20.0",
+ "@babel/plugin-syntax-dynamic-import": "^7.8.0",
+ "@babel/plugin-syntax-export-default-from": "^7.0.0",
+ "@babel/plugin-syntax-flow": "^7.18.0",
+ "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0",
+ "@babel/plugin-syntax-optional-chaining": "^7.0.0",
+ "@babel/plugin-transform-arrow-functions": "^7.0.0",
+ "@babel/plugin-transform-async-to-generator": "^7.20.0",
+ "@babel/plugin-transform-block-scoping": "^7.0.0",
+ "@babel/plugin-transform-classes": "^7.0.0",
+ "@babel/plugin-transform-computed-properties": "^7.0.0",
+ "@babel/plugin-transform-destructuring": "^7.20.0",
+ "@babel/plugin-transform-flow-strip-types": "^7.20.0",
+ "@babel/plugin-transform-function-name": "^7.0.0",
+ "@babel/plugin-transform-literals": "^7.0.0",
+ "@babel/plugin-transform-modules-commonjs": "^7.0.0",
+ "@babel/plugin-transform-named-capturing-groups-regex": "^7.0.0",
+ "@babel/plugin-transform-parameters": "^7.0.0",
+ "@babel/plugin-transform-private-methods": "^7.22.5",
+ "@babel/plugin-transform-private-property-in-object": "^7.22.11",
+ "@babel/plugin-transform-react-display-name": "^7.0.0",
+ "@babel/plugin-transform-react-jsx": "^7.0.0",
+ "@babel/plugin-transform-react-jsx-self": "^7.0.0",
+ "@babel/plugin-transform-react-jsx-source": "^7.0.0",
+ "@babel/plugin-transform-runtime": "^7.0.0",
+ "@babel/plugin-transform-shorthand-properties": "^7.0.0",
+ "@babel/plugin-transform-spread": "^7.0.0",
+ "@babel/plugin-transform-sticky-regex": "^7.0.0",
+ "@babel/plugin-transform-typescript": "^7.5.0",
+ "@babel/plugin-transform-unicode-regex": "^7.0.0",
+ "@babel/template": "^7.0.0",
+ "@react-native/babel-plugin-codegen": "0.73.2",
+ "babel-plugin-transform-flow-enums": "^0.0.2",
+ "react-refresh": "^0.14.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@babel/core": "*"
+ }
+ },
+ "node_modules/@react-native/babel-preset/node_modules/react-refresh": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
+ "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
},
"node_modules/@react-native/codegen": {
- "version": "0.72.6",
- "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.72.6.tgz",
- "integrity": "sha512-idTVI1es/oopN0jJT/0jB6nKdvTUKE3757zA5+NPXZTeB46CIRbmmos4XBiAec8ufu9/DigLPbHTYAaMNZJ6Ig==",
+ "version": "0.73.2",
+ "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.73.2.tgz",
+ "integrity": "sha512-lfy8S7umhE3QLQG5ViC4wg5N1Z+E6RnaeIw8w1voroQsXXGPB72IBozh8dAHR3+ceTxIU0KX3A8OpJI8e1+HpQ==",
"dependencies": {
"@babel/parser": "^7.20.0",
"flow-parser": "^0.206.0",
+ "glob": "^7.1.1",
+ "invariant": "^2.2.4",
"jscodeshift": "^0.14.0",
+ "mkdirp": "^0.5.1",
"nullthrows": "^1.1.1"
},
+ "engines": {
+ "node": ">=18"
+ },
"peerDependencies": {
"@babel/preset-env": "^7.1.6"
}
},
+ "node_modules/@react-native/codegen/node_modules/mkdirp": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+ "dependencies": {
+ "minimist": "^1.2.6"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
+ "node_modules/@react-native/community-cli-plugin": {
+ "version": "0.73.12",
+ "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.73.12.tgz",
+ "integrity": "sha512-xWU06OkC1cX++Duh/cD/Wv+oZ0oSY3yqbtxAqQA2H3Q+MQltNNJM6MqIHt1VOZSabRf/LVlR1JL6U9TXJirkaw==",
+ "dependencies": {
+ "@react-native-community/cli-server-api": "12.3.0",
+ "@react-native-community/cli-tools": "12.3.0",
+ "@react-native/dev-middleware": "0.73.7",
+ "@react-native/metro-babel-transformer": "0.73.13",
+ "chalk": "^4.0.0",
+ "execa": "^5.1.1",
+ "metro": "^0.80.3",
+ "metro-config": "^0.80.3",
+ "metro-core": "^0.80.3",
+ "node-fetch": "^2.2.0",
+ "readline": "^1.3.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@react-native/community-cli-plugin/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/@react-native/community-cli-plugin/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/@react-native/community-cli-plugin/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/@react-native/community-cli-plugin/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ },
+ "node_modules/@react-native/community-cli-plugin/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@react-native/community-cli-plugin/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@react-native/debugger-frontend": {
+ "version": "0.73.3",
+ "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.73.3.tgz",
+ "integrity": "sha512-RgEKnWuoo54dh7gQhV7kvzKhXZEhpF9LlMdZolyhGxHsBqZ2gXdibfDlfcARFFifPIiaZ3lXuOVVa4ei+uPgTw==",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@react-native/dev-middleware": {
+ "version": "0.73.7",
+ "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.73.7.tgz",
+ "integrity": "sha512-BZXpn+qKp/dNdr4+TkZxXDttfx8YobDh8MFHsMk9usouLm22pKgFIPkGBV0X8Do4LBkFNPGtrnsKkWk/yuUXKg==",
+ "dependencies": {
+ "@isaacs/ttlcache": "^1.4.1",
+ "@react-native/debugger-frontend": "0.73.3",
+ "chrome-launcher": "^0.15.2",
+ "chromium-edge-launcher": "^1.0.0",
+ "connect": "^3.6.5",
+ "debug": "^2.2.0",
+ "node-fetch": "^2.2.0",
+ "open": "^7.0.3",
+ "serve-static": "^1.13.1",
+ "temp-dir": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@react-native/dev-middleware/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/@react-native/dev-middleware/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "node_modules/@react-native/dev-middleware/node_modules/open": {
+ "version": "7.4.2",
+ "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz",
+ "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
+ "dependencies": {
+ "is-docker": "^2.0.0",
+ "is-wsl": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/@react-native/gradle-plugin": {
- "version": "0.72.11",
- "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.72.11.tgz",
- "integrity": "sha512-P9iRnxiR2w7EHcZ0mJ+fmbPzMby77ZzV6y9sJI3lVLJzF7TLSdbwcQyD3lwMsiL+q5lKUHoZJS4sYmih+P2HXw=="
+ "version": "0.73.4",
+ "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.73.4.tgz",
+ "integrity": "sha512-PMDnbsZa+tD55Ug+W8CfqXiGoGneSSyrBZCMb5JfiB3AFST3Uj5e6lw8SgI/B6SKZF7lG0BhZ6YHZsRZ5MlXmg==",
+ "engines": {
+ "node": ">=18"
+ }
},
"node_modules/@react-native/js-polyfills": {
- "version": "0.72.1",
- "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.72.1.tgz",
- "integrity": "sha512-cRPZh2rBswFnGt5X5EUEPs0r+pAsXxYsifv/fgy9ZLQokuT52bPH+9xjDR+7TafRua5CttGW83wP4TntRcWNDA==",
- "license": "MIT"
+ "version": "0.73.1",
+ "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.73.1.tgz",
+ "integrity": "sha512-ewMwGcumrilnF87H4jjrnvGZEaPFCAC4ebraEK+CurDDmwST/bIicI4hrOAv+0Z0F7DEK4O4H7r8q9vH7IbN4g==",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@react-native/metro-babel-transformer": {
+ "version": "0.73.13",
+ "resolved": "https://registry.npmjs.org/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.73.13.tgz",
+ "integrity": "sha512-k9AQifogQfgUXPlqQSoMtX2KUhniw4XvJl+nZ4hphCH7qiMDAwuP8OmkJbz5E/N+Ro9OFuLE7ax4GlwxaTsAWg==",
+ "dependencies": {
+ "@babel/core": "^7.20.0",
+ "@react-native/babel-preset": "0.73.19",
+ "hermes-parser": "0.15.0",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@babel/core": "*"
+ }
},
"node_modules/@react-native/metro-config": {
- "version": "0.72.11",
- "resolved": "https://registry.npmjs.org/@react-native/metro-config/-/metro-config-0.72.11.tgz",
- "integrity": "sha512-661EyQnDdVelyc0qP/ew7kKkGAh6N6KlkuPLC2SQ8sxaXskVU6fSuNlpLW4bUTBUDFKG8gEOU2hp6rzk4wQnGQ==",
+ "version": "0.73.3",
+ "resolved": "https://registry.npmjs.org/@react-native/metro-config/-/metro-config-0.73.3.tgz",
+ "integrity": "sha512-aIVh+lM52n7/RFDXLDiIp1vI21jc9thm2VxdkP7KwxMut7VvW+2tO38zKt74/2ker2ca0205tbf3pyCYBvV6Ww==",
"dev": true,
"dependencies": {
- "@react-native/js-polyfills": "^0.72.1",
- "metro-config": "0.76.8",
- "metro-react-native-babel-transformer": "0.76.8",
- "metro-runtime": "0.76.8"
+ "@react-native/js-polyfills": "0.73.1",
+ "@react-native/metro-babel-transformer": "0.73.13",
+ "metro-config": "^0.80.3",
+ "metro-runtime": "^0.80.3"
+ },
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/@react-native/normalize-color": {
@@ -10449,18 +9997,21 @@
"license": "MIT"
},
"node_modules/@react-native/normalize-colors": {
- "version": "0.72.0",
- "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.72.0.tgz",
- "integrity": "sha512-285lfdqSXaqKuBbbtP9qL2tDrfxdOFtIMvkKadtleRQkdOxx+uzGvFr82KHmc/sSiMtfXGp7JnFYWVh4sFl7Yw=="
+ "version": "0.73.2",
+ "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.73.2.tgz",
+ "integrity": "sha512-bRBcb2T+I88aG74LMVHaKms2p/T8aQd8+BZ7LuuzXlRfog1bMWWn/C5i0HVuvW4RPtXQYgIlGiXVDy9Ir1So/w=="
},
"node_modules/@react-native/virtualized-lists": {
- "version": "0.72.8",
- "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.72.8.tgz",
- "integrity": "sha512-J3Q4Bkuo99k7mu+jPS9gSUSgq+lLRSI/+ahXNwV92XgJ/8UgOTxu2LPwhJnBk/sQKxq7E8WkZBnBiozukQMqrw==",
+ "version": "0.73.4",
+ "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.73.4.tgz",
+ "integrity": "sha512-HpmLg1FrEiDtrtAbXiwCgXFYyloK/dOIPIuWW3fsqukwJEWAiTzm1nXGJ7xPU5XTHiWZ4sKup5Ebaj8z7iyWog==",
"dependencies": {
"invariant": "^2.2.4",
"nullthrows": "^1.1.1"
},
+ "engines": {
+ "node": ">=18"
+ },
"peerDependencies": {
"react-native": "*"
}
@@ -10597,6 +10148,124 @@
"loose-envify": "^1.1.0"
}
},
+ "node_modules/@remix-run/node": {
+ "version": "1.19.3",
+ "resolved": "https://registry.npmjs.org/@remix-run/node/-/node-1.19.3.tgz",
+ "integrity": "sha512-z5qrVL65xLXIUpU4mkR4MKlMeKARLepgHAk4W5YY3IBXOreRqOGUC70POViYmY7x38c2Ia1NwqL80H+0h7jbMw==",
+ "dependencies": {
+ "@remix-run/server-runtime": "1.19.3",
+ "@remix-run/web-fetch": "^4.3.6",
+ "@remix-run/web-file": "^3.0.3",
+ "@remix-run/web-stream": "^1.0.4",
+ "@web3-storage/multipart-parser": "^1.0.0",
+ "abort-controller": "^3.0.0",
+ "cookie-signature": "^1.1.0",
+ "source-map-support": "^0.5.21",
+ "stream-slice": "^0.1.2"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@remix-run/node/node_modules/cookie-signature": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.1.tgz",
+ "integrity": "sha512-78KWk9T26NhzXtuL26cIJ8/qNHANyJ/ZYrmEXFzUmhZdjpBv+DlWlOANRTGBt48YcyslsLrj0bMLFTmXvLRCOw==",
+ "engines": {
+ "node": ">=6.6.0"
+ }
+ },
+ "node_modules/@remix-run/router": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.7.2.tgz",
+ "integrity": "sha512-7Lcn7IqGMV+vizMPoEl5F0XDshcdDYtMI6uJLQdQz5CfZAwy3vvGKYSUk789qndt5dEC4HfSjviSYlSoHGL2+A==",
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@remix-run/server-runtime": {
+ "version": "1.19.3",
+ "resolved": "https://registry.npmjs.org/@remix-run/server-runtime/-/server-runtime-1.19.3.tgz",
+ "integrity": "sha512-KzQ+htUsKqpBgKE2tWo7kIIGy3MyHP58Io/itUPvV+weDjApwr9tQr9PZDPA3yAY6rAzLax7BU0NMSYCXWFY5A==",
+ "dependencies": {
+ "@remix-run/router": "1.7.2",
+ "@types/cookie": "^0.4.1",
+ "@web3-storage/multipart-parser": "^1.0.0",
+ "cookie": "^0.4.1",
+ "set-cookie-parser": "^2.4.8",
+ "source-map": "^0.7.3"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@remix-run/server-runtime/node_modules/cookie": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
+ "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/@remix-run/server-runtime/node_modules/source-map": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
+ "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@remix-run/web-blob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@remix-run/web-blob/-/web-blob-3.1.0.tgz",
+ "integrity": "sha512-owGzFLbqPH9PlKb8KvpNJ0NO74HWE2euAn61eEiyCXX/oteoVzTVSN8mpLgDjaxBf2btj5/nUllSUgpyd6IH6g==",
+ "dependencies": {
+ "@remix-run/web-stream": "^1.1.0",
+ "web-encoding": "1.1.5"
+ }
+ },
+ "node_modules/@remix-run/web-fetch": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/@remix-run/web-fetch/-/web-fetch-4.4.2.tgz",
+ "integrity": "sha512-jgKfzA713/4kAW/oZ4bC3MoLWyjModOVDjFPNseVqcJKSafgIscrYL9G50SurEYLswPuoU3HzSbO0jQCMYWHhA==",
+ "dependencies": {
+ "@remix-run/web-blob": "^3.1.0",
+ "@remix-run/web-file": "^3.1.0",
+ "@remix-run/web-form-data": "^3.1.0",
+ "@remix-run/web-stream": "^1.1.0",
+ "@web3-storage/multipart-parser": "^1.0.0",
+ "abort-controller": "^3.0.0",
+ "data-uri-to-buffer": "^3.0.1",
+ "mrmime": "^1.0.0"
+ },
+ "engines": {
+ "node": "^10.17 || >=12.3"
+ }
+ },
+ "node_modules/@remix-run/web-file": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@remix-run/web-file/-/web-file-3.1.0.tgz",
+ "integrity": "sha512-dW2MNGwoiEYhlspOAXFBasmLeYshyAyhIdrlXBi06Duex5tDr3ut2LFKVj7tyHLmn8nnNwFf1BjNbkQpygC2aQ==",
+ "dependencies": {
+ "@remix-run/web-blob": "^3.1.0"
+ }
+ },
+ "node_modules/@remix-run/web-form-data": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@remix-run/web-form-data/-/web-form-data-3.1.0.tgz",
+ "integrity": "sha512-NdeohLMdrb+pHxMQ/Geuzdp0eqPbea+Ieo8M8Jx2lGC6TBHsgHzYcBvr0LyPdPVycNRDEpWpiDdCOdCryo3f9A==",
+ "dependencies": {
+ "web-encoding": "1.1.5"
+ }
+ },
+ "node_modules/@remix-run/web-stream": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@remix-run/web-stream/-/web-stream-1.1.0.tgz",
+ "integrity": "sha512-KRJtwrjRV5Bb+pM7zxcTJkhIqWWSy+MYsIxHK+0m5atcznsf15YwUBWHWulZerV2+vvHH1Lp1DD7pw6qKW8SgA==",
+ "dependencies": {
+ "web-streams-polyfill": "^3.1.1"
+ }
+ },
"node_modules/@rnmapbox/maps": {
"version": "10.0.11",
"resolved": "https://registry.npmjs.org/@rnmapbox/maps/-/maps-10.0.11.tgz",
@@ -10707,9 +10376,9 @@
"license": "0BSD"
},
"node_modules/@shopify/flash-list": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@shopify/flash-list/-/flash-list-1.6.1.tgz",
- "integrity": "sha512-SlBlpP7+zol6D1SKaf402aS30Qgwdjwb8/Qn2CupYwXnTcu2l8TiXB766vcsIvKTqUO7ELfQnCwCq8NXx55FsQ==",
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/@shopify/flash-list/-/flash-list-1.6.3.tgz",
+ "integrity": "sha512-XM2iu4CeD9SOEUxaGG3UkxfUxGPWG9yacga1yQSgskAjUsRDFTsD3y4Dyon9n8MfDwgrRpEwuijd+7NeQQoWaQ==",
"dependencies": {
"recyclerlistview": "4.2.0",
"tslib": "2.4.0"
@@ -20916,6 +20585,12 @@
"@types/responselike": "^1.0.0"
}
},
+ "node_modules/@types/canvas-size": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@types/canvas-size/-/canvas-size-1.2.2.tgz",
+ "integrity": "sha512-yuTXFWC4tHV3lt5ZtbIP9VeeMNbDYm5mPyqaQnaMuSSx2mjsfZGXMNmHTnfdsR5qZdB6dtbaV5IP2PKv79vmKg==",
+ "dev": true
+ },
"node_modules/@types/concurrently": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@types/concurrently/-/concurrently-7.0.0.tgz",
@@ -20945,6 +20620,11 @@
"@types/node": "*"
}
},
+ "node_modules/@types/cookie": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
+ "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
+ },
"node_modules/@types/debug": {
"version": "4.1.8",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz",
@@ -21374,9 +21054,9 @@
"license": "MIT"
},
"node_modules/@types/react": {
- "version": "18.2.12",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.12.tgz",
- "integrity": "sha512-ndmBMLCgn38v3SntMeoJaIrO6tGHYKMEBohCUmw8HoLLQdRMOIGXfeYaBTLe2lsFaSB3MOK1VXscYFnmLtTSmw==",
+ "version": "18.2.45",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.45.tgz",
+ "integrity": "sha512-TtAxCNrlrBp8GoeEp1npd5g+d/OejJHFxS3OWmrPBMFaVQMSN0OFySozJio5BHxTuTeug00AVXVAjfDSfk+lUg==",
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "*",
@@ -22327,6 +22007,11 @@
"webpack": "^5.20.0 || ^4.1.0"
}
},
+ "node_modules/@web3-storage/multipart-parser": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@web3-storage/multipart-parser/-/multipart-parser-1.0.0.tgz",
+ "integrity": "sha512-BEO6al7BYqcnfX15W2cnGR+Q566ACXAT9UQykORCWW80lmkpWsnEob6zJS1ZVBKsSJC8+7vJkHwlp+lXG1UCdw=="
+ },
"node_modules/@webassemblyjs/ast": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz",
@@ -22685,6 +22370,12 @@
"integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==",
"license": "BSD-2-Clause"
},
+ "node_modules/@zxing/text-encoding": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz",
+ "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==",
+ "optional": true
+ },
"node_modules/7zip-bin": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.1.1.tgz",
@@ -24340,6 +24031,7 @@
},
"node_modules/babel-plugin-module-resolver": {
"version": "5.0.0",
+ "dev": true,
"license": "MIT",
"dependencies": {
"find-babel-config": "^2.0.0",
@@ -24354,6 +24046,7 @@
},
"node_modules/babel-plugin-module-resolver/node_modules/brace-expansion": {
"version": "2.0.1",
+ "dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
@@ -24363,6 +24056,7 @@
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
"integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
+ "dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
@@ -24381,6 +24075,7 @@
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "dev": true,
"dependencies": {
"brace-expansion": "^2.0.1"
},
@@ -24542,18 +24237,27 @@
}
},
"node_modules/babel-preset-expo": {
- "version": "9.5.2",
- "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-9.5.2.tgz",
- "integrity": "sha512-hU1G1TDiikuXV6UDZjPnX+WdbjbtidDiYhftMEVrZQSst45pDPVBWbM41TUKrpJMwv4FypsLzK+378gnMPRVWQ==",
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-10.0.1.tgz",
+ "integrity": "sha512-uWIGmLfbP3dS5+8nesxaW6mQs41d4iP7X82ZwRdisB/wAhKQmuJM9Y1jQe4006uNYkw6Phf2TT03ykLVro7KuQ==",
"dependencies": {
"@babel/plugin-proposal-decorators": "^7.12.9",
- "@babel/plugin-proposal-export-namespace-from": "^7.18.9",
- "@babel/plugin-proposal-object-rest-spread": "^7.12.13",
- "@babel/plugin-transform-react-jsx": "^7.12.17",
+ "@babel/plugin-transform-export-namespace-from": "^7.22.11",
+ "@babel/plugin-transform-object-rest-spread": "^7.12.13",
+ "@babel/plugin-transform-parameters": "^7.22.15",
"@babel/preset-env": "^7.20.0",
- "babel-plugin-module-resolver": "^5.0.0",
+ "@babel/preset-react": "^7.22.15",
+ "@react-native/babel-preset": "^0.73.18",
"babel-plugin-react-native-web": "~0.18.10",
- "metro-react-native-babel-preset": "0.76.8"
+ "react-refresh": "0.14.0"
+ }
+ },
+ "node_modules/babel-preset-expo/node_modules/react-refresh": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
+ "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==",
+ "engines": {
+ "node": ">=0.10.0"
}
},
"node_modules/babel-preset-fbjs": {
@@ -24776,6 +24480,14 @@
"node": ">=0.10.0"
}
},
+ "node_modules/base64-arraybuffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
+ "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -26134,6 +25846,23 @@
"node": ">=10"
}
},
+ "node_modules/chrome-launcher": {
+ "version": "0.15.2",
+ "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz",
+ "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==",
+ "dependencies": {
+ "@types/node": "*",
+ "escape-string-regexp": "^4.0.0",
+ "is-wsl": "^2.2.0",
+ "lighthouse-logger": "^1.0.0"
+ },
+ "bin": {
+ "print-chrome-path": "bin/print-chrome-path.js"
+ },
+ "engines": {
+ "node": ">=12.13.0"
+ }
+ },
"node_modules/chrome-trace-event": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
@@ -26143,6 +25872,19 @@
"node": ">=6.0"
}
},
+ "node_modules/chromium-edge-launcher": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-1.0.0.tgz",
+ "integrity": "sha512-pgtgjNKZ7i5U++1g1PWv75umkHvhVTDOQIZ+sjeUX9483S7Y6MUvO0lrd7ShGlQlFHMN4SwKTCq/X8hWrbv2KA==",
+ "dependencies": {
+ "@types/node": "*",
+ "escape-string-regexp": "^4.0.0",
+ "is-wsl": "^2.2.0",
+ "lighthouse-logger": "^1.0.0",
+ "mkdirp": "^1.0.4",
+ "rimraf": "^3.0.2"
+ }
+ },
"node_modules/chromium-pickle-js": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz",
@@ -26357,9 +26099,9 @@
}
},
"node_modules/cli-spinners": {
- "version": "2.9.1",
- "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.1.tgz",
- "integrity": "sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==",
+ "version": "2.9.2",
+ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz",
+ "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==",
"engines": {
"node": ">=6"
},
@@ -26411,10 +26153,9 @@
}
},
"node_modules/clipboard": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.4.tgz",
- "integrity": "sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==",
- "license": "MIT",
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz",
+ "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==",
"dependencies": {
"good-listener": "^1.2.2",
"select": "^1.1.2",
@@ -26742,11 +26483,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/compare-versions": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz",
- "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA=="
- },
"node_modules/complex.js": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.1.1.tgz",
@@ -26768,9 +26504,12 @@
"license": "MIT"
},
"node_modules/component-type": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/component-type/-/component-type-1.2.1.tgz",
- "integrity": "sha512-Kgy+2+Uwr75vAi6ChWXgHuLvd+QLD7ssgpaRq2zCvt80ptvAfMc/hijcJxXkBa2wMlEZcJvC2H8Ubo+A9ATHIg=="
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/component-type/-/component-type-1.2.2.tgz",
+ "integrity": "sha512-99VUHREHiN5cLeHm3YLq312p6v+HUEcwtLCAtelvUDI6+SH5g5Cr85oNR2S1o6ywzL0ykMbuwLzM2ANocjEOIA==",
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
},
"node_modules/compressible": {
"version": "2.0.18",
@@ -27829,6 +27568,14 @@
"isobject": "^3.0.1"
}
},
+ "node_modules/css-line-break": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
+ "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
+ "dependencies": {
+ "utrie": "^1.0.2"
+ }
+ },
"node_modules/css-loader": {
"version": "6.8.1",
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz",
@@ -28157,6 +27904,14 @@
"dev": true,
"license": "BSD-2-Clause"
},
+ "node_modules/data-uri-to-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz",
+ "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/data-urls": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz",
@@ -28547,8 +28302,7 @@
"node_modules/delegate": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
- "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==",
- "license": "MIT"
+ "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw=="
},
"node_modules/delegates": {
"version": "1.0.0",
@@ -29058,8 +28812,7 @@
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
- "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
- "dev": true
+ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
},
"node_modules/ee-first": {
"version": "1.1.1",
@@ -29576,8 +29329,9 @@
}
},
"node_modules/envinfo": {
- "version": "7.8.1",
- "license": "MIT",
+ "version": "7.11.0",
+ "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.0.tgz",
+ "integrity": "sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg==",
"bin": {
"envinfo": "dist/cli.js"
},
@@ -31838,37 +31592,26 @@
},
"node_modules/expensify-common": {
"version": "1.0.0",
- "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#398bf7c6a6d37f229a41d92bd7a4324c0fd32849",
- "integrity": "sha512-H7UrLgWIr8mCoPc1oxbeYW2RwLzUWI6jdjbV6cRnrlp8cDW3IyZISF+BQSPFDj7bMhNAbczQPtEOE1gld21Cvg==",
+ "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#c6bb3cfa56d12af9fa02e2bfc729646f5b64ef44",
+ "integrity": "sha512-a/UBkrerB57nB9xbBrFIeJG3IN0lVZV+/JWNbGMfT0FHxtg8/4sGWdC+AHqR3Bm01gwt67dd2csFferlZmTIsg==",
"license": "MIT",
"dependencies": {
"classnames": "2.3.1",
- "clipboard": "2.0.4",
- "html-entities": "^2.3.3",
+ "clipboard": "2.0.11",
+ "html-entities": "^2.4.0",
"jquery": "3.6.0",
"localforage": "^1.10.0",
"lodash": "4.17.21",
- "prop-types": "15.7.2",
+ "prop-types": "15.8.1",
"react": "16.12.0",
"react-dom": "16.12.0",
- "semver": "^7.3.5",
+ "semver": "^7.5.2",
"simply-deferred": "git+https://github.com/Expensify/simply-deferred.git#77a08a95754660c7bd6e0b6979fdf84e8e831bf5",
- "string.prototype.replaceall": "^1.0.6",
+ "string.prototype.replaceall": "^1.0.8",
"ua-parser-js": "^1.0.35",
"underscore": "1.13.6"
}
},
- "node_modules/expensify-common/node_modules/prop-types": {
- "version": "15.7.2",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
- "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
- "license": "MIT",
- "dependencies": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.8.1"
- }
- },
"node_modules/expensify-common/node_modules/react": {
"version": "16.12.0",
"resolved": "https://registry.npmjs.org/react/-/react-16.12.0.tgz",
@@ -31928,107 +31671,66 @@
}
},
"node_modules/expo": {
- "version": "49.0.21",
- "resolved": "https://registry.npmjs.org/expo/-/expo-49.0.21.tgz",
- "integrity": "sha512-JpHL6V0yt8/fzsmkAdPdtsah+lU6Si4ac7MDklLYvzEil7HAFEsN/pf06wQ21ax4C+BL27hI6JJoD34tzXUCJA==",
+ "version": "50.0.0-preview.7",
+ "resolved": "https://registry.npmjs.org/expo/-/expo-50.0.0-preview.7.tgz",
+ "integrity": "sha512-FyoEJVf42Tr1On0IFa0dL7Qs9gnl252ah3e0B8FsU96G7Hi93cDz5Rcn81ezRiO6YIF4nFV3+bh6BHsm/nsA0A==",
"dependencies": {
"@babel/runtime": "^7.20.0",
- "@expo/cli": "0.10.16",
- "@expo/config": "8.1.2",
- "@expo/config-plugins": "7.2.5",
+ "@expo/cli": "0.16.5",
+ "@expo/config": "8.5.2",
+ "@expo/config-plugins": "7.8.2",
+ "@expo/metro-config": "0.17.1",
"@expo/vector-icons": "^13.0.0",
- "babel-preset-expo": "~9.5.2",
- "expo-application": "~5.3.0",
- "expo-asset": "~8.10.1",
- "expo-constants": "~14.4.2",
- "expo-file-system": "~15.4.5",
- "expo-font": "~11.4.0",
- "expo-keep-awake": "~12.3.0",
- "expo-modules-autolinking": "1.5.1",
- "expo-modules-core": "1.5.12",
+ "babel-preset-expo": "~10.0.1",
+ "expo-asset": "~9.0.1",
+ "expo-file-system": "~16.0.2",
+ "expo-font": "~11.10.0",
+ "expo-keep-awake": "~12.8.0",
+ "expo-modules-autolinking": "1.9.0",
+ "expo-modules-core": "1.11.4",
"fbemitter": "^3.0.0",
- "invariant": "^2.2.4",
- "md5-file": "^3.2.3",
- "node-fetch": "^2.6.7",
- "pretty-format": "^26.5.2",
- "uuid": "^3.4.0"
+ "whatwg-url-without-unicode": "8.0.0-3"
},
"bin": {
"expo": "bin/cli"
}
},
- "node_modules/expo-application": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/expo-application/-/expo-application-5.3.1.tgz",
- "integrity": "sha512-HR2+K+Hm33vLw/TfbFaHrvUbRRNRco8R+3QaCKy7eJC2LFfT05kZ15ynGaKfB5DJ/oqPV3mxXVR/EfwmE++hoA==",
- "peerDependencies": {
- "expo": "*"
- }
- },
"node_modules/expo-asset": {
- "version": "8.10.1",
- "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-8.10.1.tgz",
- "integrity": "sha512-5VMTESxgY9GBsspO/esY25SKEa7RyascVkLe/OcL1WgblNFm7xCCEEUIW8VWS1nHJQGYxpMZPr3bEfjMpdWdyA==",
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-9.0.1.tgz",
+ "integrity": "sha512-hoCzQ8ga6ZOmkwABQeAIStXmshpK+1oNpGNNeJCJ1QdoU6hlCu6DKnikreLZYr6FQzaQTS3yel86zuRQtwNpaQ==",
"dependencies": {
+ "@react-native/assets-registry": "~0.73.1",
"blueimp-md5": "^2.10.0",
- "expo-constants": "~14.4.2",
- "expo-file-system": "~15.4.0",
+ "expo-constants": "~15.4.0",
+ "expo-file-system": "~16.0.0",
"invariant": "^2.2.4",
- "md5-file": "^3.2.3",
- "path-browserify": "^1.0.0",
- "url-parse": "^1.5.9"
+ "md5-file": "^3.2.3"
}
},
- "node_modules/expo-asset/node_modules/path-browserify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
- "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="
- },
"node_modules/expo-constants": {
- "version": "14.4.2",
- "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-14.4.2.tgz",
- "integrity": "sha512-nOB122DOAjk+KrJT69lFQAoYVQGQjFHSigCPVBzVdko9S1xGsfiOH9+X5dygTsZTIlVLpQJDdmZ7ONiv3i+26w==",
+ "version": "15.4.2",
+ "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-15.4.2.tgz",
+ "integrity": "sha512-goJ44MsjRkJQbi/w49n7HIsBnp7Caa4mPMDUgTwk07BCUM5yKPb3Ny2/0QsaUcqBNgke2IXxr4OhqDYLd1jWOQ==",
"dependencies": {
- "@expo/config": "~8.1.0",
- "uuid": "^3.3.2"
+ "@expo/config": "~8.5.0"
},
"peerDependencies": {
"expo": "*"
}
},
- "node_modules/expo-constants/node_modules/uuid": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
- "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
- "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
- "bin": {
- "uuid": "bin/uuid"
- }
- },
"node_modules/expo-file-system": {
- "version": "15.4.5",
- "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-15.4.5.tgz",
- "integrity": "sha512-xy61KaTaDgXhT/dllwYDHm3ch026EyO8j4eC6wSVr/yE12MMMxAC09yGwy4f7kkOs6ztGVQF5j7ldRzNLN4l0Q==",
- "dependencies": {
- "uuid": "^3.4.0"
- },
+ "version": "16.0.2",
+ "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-16.0.2.tgz",
+ "integrity": "sha512-oqiM3aq4mGugdv6DRH0wjrULWdZFm4EMLgKmR24on/f9ZCDG9VB3waSy+9J3XaDTAXBaB9ta82ACnNzk8KPdMw==",
"peerDependencies": {
"expo": "*"
}
},
- "node_modules/expo-file-system/node_modules/uuid": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
- "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
- "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
- "bin": {
- "uuid": "bin/uuid"
- }
- },
"node_modules/expo-font": {
- "version": "11.4.0",
- "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-11.4.0.tgz",
- "integrity": "sha512-nkmezCFD7gR/I6R+e3/ry18uEfF8uYrr6h+PdBJu+3dawoLOpo+wFb/RG9bHUekU1/cPanR58LR7G5MEMKHR2w==",
+ "version": "11.10.0",
+ "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-11.10.0.tgz",
+ "integrity": "sha512-yqlsoOKWiYv8aBMFqheHSUKKEY/lrB7zHjzDc60OF1xGa1q8kh7mKQVwSaRMS0G77GEUvvk8Vb/uKw51KY1kGA==",
"dependencies": {
"fontfaceobserver": "^2.1.0"
},
@@ -32037,27 +31739,30 @@
}
},
"node_modules/expo-image": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/expo-image/-/expo-image-1.8.1.tgz",
- "integrity": "sha512-YHoP3F6zRcI9ULjB84jPt62ggSrdGLtpSxZTUxwmfI+WfuucNd/zqqXx0edsCyREIA6VvoyWBT48BBgvi+H1TA==",
+ "version": "1.10.1",
+ "resolved": "https://registry.npmjs.org/expo-image/-/expo-image-1.10.1.tgz",
+ "integrity": "sha512-NwJt2FS6sZXeP92RpsZxBKSnCPWMdcJ2Q2bXHc8WgOkLLInvRd0yBKAzEusXTZ6+N+RqAcWVojlh3EBbSQhkiA==",
+ "dependencies": {
+ "@react-native/assets-registry": "~0.73.1"
+ },
"peerDependencies": {
"expo": "*"
}
},
"node_modules/expo-keep-awake": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-12.3.0.tgz",
- "integrity": "sha512-ujiJg1p9EdCOYS05jh5PtUrfiZnK0yyLy+UewzqrjUqIT8eAGMQbkfOn3C3fHE7AKd5AefSMzJnS3lYZcZYHDw==",
+ "version": "12.8.0",
+ "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-12.8.0.tgz",
+ "integrity": "sha512-KMk9nnOEEI2w4aYr/PMnLT6ryXwmHfsb/baeHX/RSLNBZ4a5JVkNXP+mT66UNnYfXxy3pABruusd7KjeKW+F0A==",
"peerDependencies": {
"expo": "*"
}
},
"node_modules/expo-modules-autolinking": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-1.5.1.tgz",
- "integrity": "sha512-yt5a1VCp2BF9CrsO689PCD5oXKP14MMhnOanQMvDn4BDpURYfzAlDVGC5fZrNQKtwn/eq3bcrxIwZ7D9QjVVRg==",
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-1.9.0.tgz",
+ "integrity": "sha512-FVRuclmR7w6FZRXZmTwPdIr9PNCP7FUWMhpzaxbKU/xm7DbNw5ORAv2gaM8t9OaMxYjIAMSNYi0NnmLIinzBKA==",
"dependencies": {
- "@expo/config": "~8.1.0",
+ "@expo/config": "~8.5.0",
"chalk": "^4.1.0",
"commander": "^7.2.0",
"fast-glob": "^3.2.5",
@@ -32141,11 +31846,10 @@
}
},
"node_modules/expo-modules-core": {
- "version": "1.5.12",
- "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-1.5.12.tgz",
- "integrity": "sha512-mY4wTDU458dhwk7IVxLNkePlYXjs9BTgk4NQHBUXf0LapXsvr+i711qPZaFNO4egf5qq6fQV+Yfd/KUguHstnQ==",
+ "version": "1.11.4",
+ "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-1.11.4.tgz",
+ "integrity": "sha512-MeDvWvdI3cHJO2VsASXsNYVoou1sdEO/SGBdLh2lxRhNpCLB0IIEZ3uPZwQQ8WBfFyPk4QT7M3XhCdPCKaT21A==",
"dependencies": {
- "compare-versions": "^3.4.0",
"invariant": "^2.2.4"
}
},
@@ -32158,13 +31862,14 @@
}
},
"node_modules/expo/node_modules/@expo/config-plugins": {
- "version": "7.2.5",
- "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.2.5.tgz",
- "integrity": "sha512-w+5ccu1IxBHgyQk9CPFKLZOk8yZQEyTjbJwOzESK1eR7QwosbcsLkN1c1WWUZYiCXwORu3UTwJYll4+X2xxJhQ==",
- "dependencies": {
- "@expo/config-types": "^49.0.0-alpha.1",
- "@expo/json-file": "~8.2.37",
- "@expo/plist": "^0.0.20",
+ "version": "7.8.2",
+ "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.8.2.tgz",
+ "integrity": "sha512-XM2eXA5EvcpmXFCui48+bVy8GTskYSjPf2yC+LliYv8PDcedu7+pdgmbnvH4eZCyHfTMO8/UiF+w8e5WgOEj5A==",
+ "dependencies": {
+ "@expo/config-types": "^50.0.0-alpha.1",
+ "@expo/fingerprint": "^0.6.0",
+ "@expo/json-file": "~8.3.0",
+ "@expo/plist": "^0.1.0",
"@expo/sdk-runtime-versions": "^1.0.0",
"@react-native/normalize-color": "^2.0.0",
"chalk": "^4.1.2",
@@ -32175,19 +31880,20 @@
"resolve-from": "^5.0.0",
"semver": "^7.5.3",
"slash": "^3.0.0",
+ "slugify": "^1.6.6",
"xcode": "^3.0.1",
"xml2js": "0.6.0"
}
},
"node_modules/expo/node_modules/@expo/config-types": {
- "version": "49.0.0",
- "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-49.0.0.tgz",
- "integrity": "sha512-8eyREVi+K2acnMBe/rTIu1dOfyR2+AMnTLHlut+YpMV9OZPdeKV0Bs9BxAewGqBA2slslbQ9N39IS2CuTKpXkA=="
+ "version": "50.0.0",
+ "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-50.0.0.tgz",
+ "integrity": "sha512-0kkhIwXRT6EdFDwn+zTg9R2MZIAEYGn1MVkyRohAd+C9cXOb5RA8WLQi7vuxKF9m1SMtNAUrf0pO+ENK0+/KSw=="
},
"node_modules/expo/node_modules/@expo/json-file": {
- "version": "8.2.37",
- "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.2.37.tgz",
- "integrity": "sha512-YaH6rVg11JoTS2P6LsW7ybS2CULjf40AbnAHw2F1eDPuheprNjARZMnyHFPkKv7GuxCy+B9GPcbOKgc4cgA80Q==",
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.3.0.tgz",
+ "integrity": "sha512-yROUeXJXR5goagB8c3muFLCzLmdGOvoPpR5yDNaXrnTp4euNykr9yW0wWhJx4YVRTNOPtGBnEbbJBW+a9q+S6g==",
"dependencies": {
"@babel/code-frame": "~7.10.4",
"json5": "^2.2.2",
@@ -32195,23 +31901,15 @@
}
},
"node_modules/expo/node_modules/@expo/plist": {
- "version": "0.0.20",
- "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.0.20.tgz",
- "integrity": "sha512-UXQ4LXCfTZ580LDHGJ5q62jSTwJFFJ1GqBu8duQMThiHKWbMJ+gajJh6rsB6EJ3aLUr9wcauxneL5LVRFxwBEA==",
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.1.0.tgz",
+ "integrity": "sha512-xWD+8vIFif0wKyuqe3fmnmnSouXYucciZXFzS0ZD5OV9eSAS1RGQI5FaGGJ6zxJ4mpdy/4QzbLdBjnYE5vxA0g==",
"dependencies": {
"@xmldom/xmldom": "~0.7.7",
"base64-js": "^1.2.3",
"xmlbuilder": "^14.0.0"
}
},
- "node_modules/expo/node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/expo/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@@ -32265,25 +31963,6 @@
"node": ">=8"
}
},
- "node_modules/expo/node_modules/pretty-format": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz",
- "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==",
- "dependencies": {
- "@jest/types": "^26.6.2",
- "ansi-regex": "^5.0.0",
- "ansi-styles": "^4.0.0",
- "react-is": "^17.0.1"
- },
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/expo/node_modules/react-is": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
- "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
- },
"node_modules/expo/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -32295,15 +31974,6 @@
"node": ">=8"
}
},
- "node_modules/expo/node_modules/uuid": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
- "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
- "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
- "bin": {
- "uuid": "bin/uuid"
- }
- },
"node_modules/expo/node_modules/xml2js": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.0.tgz",
@@ -32636,17 +32306,17 @@
"license": "MIT"
},
"node_modules/fast-xml-parser": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.1.tgz",
- "integrity": "sha512-viVv3xb8D+SiS1W4cv4tva3bni08kAkx0gQnWrykMM8nXPc1FxqZPU00dCEVjkiCg4HoXd2jC4x29Nzg/l2DAA==",
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.2.tgz",
+ "integrity": "sha512-rmrXUXwbJedoXkStenj1kkljNF7ugn5ZjR9FJcwmCfcCbtOMDghPajbc+Tck6vE6F5XsDmx+Pr2le9fw8+pXBg==",
"funding": [
- {
- "type": "paypal",
- "url": "https://paypal.me/naturalintelligence"
- },
{
"type": "github",
"url": "https://github.com/sponsors/NaturalIntelligence"
+ },
+ {
+ "type": "paypal",
+ "url": "https://paypal.me/naturalintelligence"
}
],
"dependencies": {
@@ -32940,6 +32610,7 @@
},
"node_modules/find-babel-config": {
"version": "2.0.0",
+ "dev": true,
"license": "MIT",
"dependencies": {
"json5": "^2.1.1",
@@ -32951,6 +32622,7 @@
},
"node_modules/find-babel-config/node_modules/path-exists": {
"version": "4.0.0",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -33089,9 +32761,9 @@
"dev": true
},
"node_modules/flow-enums-runtime": {
- "version": "0.0.5",
- "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.5.tgz",
- "integrity": "sha512-PSZF9ZuaZD03sT9YaIs0FrGJ7lSUw7rHZIex+73UYVXg46eL/wxN5PaVcPJFudE2cJu5f0fezitV5aBkLHPUOQ=="
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz",
+ "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw=="
},
"node_modules/flow-parser": {
"version": "0.206.0",
@@ -33854,7 +33526,6 @@
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
"integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==",
- "license": "MIT",
"dependencies": {
"delegate": "^3.1.2"
}
@@ -34497,16 +34168,16 @@
}
},
"node_modules/hermes-estree": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.12.0.tgz",
- "integrity": "sha512-+e8xR6SCen0wyAKrMT3UD0ZCCLymKhRgjEB5sS28rKiFir/fXgLoeRilRUssFCILmGHb+OvHDUlhxs0+IEyvQw=="
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.15.0.tgz",
+ "integrity": "sha512-lLYvAd+6BnOqWdnNbP/Q8xfl8LOGw4wVjfrNd9Gt8eoFzhNBRVD95n4l2ksfMVOoxuVyegs85g83KS9QOsxbVQ=="
},
"node_modules/hermes-parser": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.12.0.tgz",
- "integrity": "sha512-d4PHnwq6SnDLhYl3LHNHvOg7nQ6rcI7QVil418REYksv0Mh3cEkHDcuhGxNQ3vgnLSLl4QSvDrFCwQNYdpWlzw==",
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.15.0.tgz",
+ "integrity": "sha512-Q1uks5rjZlE9RjMMjSUCkGrEIPI5pKJILeCtK1VmTj7U4pf3wVPoo+cxfu+s4cBAPy2JzikIIdCZgBoR6x7U1Q==",
"dependencies": {
- "hermes-estree": "0.12.0"
+ "hermes-estree": "0.15.0"
}
},
"node_modules/hermes-profile-transformer": {
@@ -34599,9 +34270,19 @@
}
},
"node_modules/html-entities": {
- "version": "2.3.5",
- "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.5.tgz",
- "integrity": "sha512-72TJlcMkYsEJASa/3HnX7VT59htM7iSHbH59NSZbtc+22Ap0Txnlx91sfeB+/A7wNZg7UxtZdhAW4y+/jimrdg=="
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz",
+ "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/mdevils"
+ },
+ {
+ "type": "patreon",
+ "url": "https://patreon.com/mdevils"
+ }
+ ]
},
"node_modules/html-escaper": {
"version": "2.0.2",
@@ -34692,6 +34373,18 @@
"node": ">=6"
}
},
+ "node_modules/html2canvas": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
+ "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
+ "dependencies": {
+ "css-line-break": "^2.1.0",
+ "text-segmentation": "^1.0.3"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
"node_modules/htmlparser2": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz",
@@ -35247,9 +34940,9 @@
}
},
"node_modules/image-size": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz",
- "integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.1.1.tgz",
+ "integrity": "sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==",
"dependencies": {
"queue": "6.0.2"
},
@@ -35257,7 +34950,7 @@
"image-size": "bin/image-size.js"
},
"engines": {
- "node": ">=14.0.0"
+ "node": ">=16.x"
}
},
"node_modules/immediate": {
@@ -35790,7 +35483,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"call-bind": "^1.0.2",
@@ -36117,7 +35809,6 @@
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
"integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
- "dev": true,
"dependencies": {
"has-tostringtag": "^1.0.0"
},
@@ -36716,10 +36407,9 @@
}
},
"node_modules/jackspeak": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.1.tgz",
- "integrity": "sha512-MXbxovZ/Pm42f6cDIDkl3xpwv1AGwObKwfmjs2nQePiy85tP3fatofl3FC1aBsOtP/6fq5SbtgHwWcMsLP+bDw==",
- "dev": true,
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz",
+ "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==",
"dependencies": {
"@isaacs/cliui": "^8.0.2"
},
@@ -37624,25 +37314,27 @@
}
},
"node_modules/jest-environment-node": {
- "version": "29.4.1",
- "license": "MIT",
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz",
+ "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==",
"dependencies": {
- "@jest/environment": "^29.4.1",
- "@jest/fake-timers": "^29.4.1",
- "@jest/types": "^29.4.1",
+ "@jest/environment": "^29.7.0",
+ "@jest/fake-timers": "^29.7.0",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
- "jest-mock": "^29.4.1",
- "jest-util": "^29.4.1"
+ "jest-mock": "^29.7.0",
+ "jest-util": "^29.7.0"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/jest-environment-node/node_modules/@jest/types": {
- "version": "29.4.1",
- "license": "MIT",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz",
+ "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
"dependencies": {
- "@jest/schemas": "^29.4.0",
+ "@jest/schemas": "^29.6.3",
"@types/istanbul-lib-coverage": "^2.0.0",
"@types/istanbul-reports": "^3.0.0",
"@types/node": "*",
@@ -37654,9 +37346,9 @@
}
},
"node_modules/jest-environment-node/node_modules/@types/yargs": {
- "version": "17.0.24",
- "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz",
- "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==",
+ "version": "17.0.31",
+ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.31.tgz",
+ "integrity": "sha512-bocYSx4DI8TmdlvxqGpVNXOgCNR1Jj0gNPhhAY+iz1rgKDAaYrAYdFYnhDV1IFuiuVc9HkOwyDcFxaTElF3/wg==",
"dependencies": {
"@types/yargs-parser": "*"
}
@@ -37665,7 +37357,6 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
@@ -37680,7 +37371,6 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "license": "MIT",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -37696,7 +37386,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
@@ -37707,14 +37396,12 @@
"node_modules/jest-environment-node/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "license": "MIT"
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/jest-environment-node/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "license": "MIT",
"engines": {
"node": ">=8"
}
@@ -37723,7 +37410,6 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -37732,11 +37418,12 @@
}
},
"node_modules/jest-expo": {
- "version": "49.0.0",
- "resolved": "https://registry.npmjs.org/jest-expo/-/jest-expo-49.0.0.tgz",
- "integrity": "sha512-nglYg6QPYSqCsrsOFiGosQi+m1rrqmYluPbFXNnXNEOrB2MvxMOgQJeWfMHDExHMX1ymLWX+7y8mYo6XVJpBJQ==",
+ "version": "50.0.1",
+ "resolved": "https://registry.npmjs.org/jest-expo/-/jest-expo-50.0.1.tgz",
+ "integrity": "sha512-osvA63UDLJ/v7MG9UHjU7WJ0oZ0Krq9UhXxm2s6rdOlnt85ARocyMU57RC0T0yzPN47C9Ref45sEeOIxoV4Mzg==",
"dependencies": {
- "@expo/config": "~8.1.0",
+ "@expo/config": "~8.5.0",
+ "@expo/json-file": "^8.2.37",
"@jest/create-cache-key-function": "^29.2.1",
"babel-jest": "^29.2.1",
"find-up": "^5.0.0",
@@ -37745,12 +37432,31 @@
"jest-watch-typeahead": "2.2.1",
"json5": "^2.2.3",
"lodash": "^4.17.19",
- "react-test-renderer": "18.2.0"
+ "react-test-renderer": "18.2.0",
+ "stacktrace-js": "^2.0.2"
},
"bin": {
"jest": "bin/jest.js"
}
},
+ "node_modules/jest-expo/node_modules/@babel/code-frame": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
+ "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
+ "dependencies": {
+ "@babel/highlight": "^7.10.4"
+ }
+ },
+ "node_modules/jest-expo/node_modules/@expo/json-file": {
+ "version": "8.2.37",
+ "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.2.37.tgz",
+ "integrity": "sha512-YaH6rVg11JoTS2P6LsW7ybS2CULjf40AbnAHw2F1eDPuheprNjARZMnyHFPkKv7GuxCy+B9GPcbOKgc4cgA80Q==",
+ "dependencies": {
+ "@babel/code-frame": "~7.10.4",
+ "json5": "^2.2.2",
+ "write-file-atomic": "^2.3.0"
+ }
+ },
"node_modules/jest-get-type": {
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz",
@@ -37995,17 +37701,17 @@
}
},
"node_modules/jest-message-util": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.2.tgz",
- "integrity": "sha512-vnIGYEjoPSuRqV8W9t+Wow95SDp6KPX2Uf7EoeG9G99J2OVh7OSwpS4B6J0NfpEIpfkBNHlBZpA2rblEuEFhZQ==",
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz",
+ "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==",
"dependencies": {
"@babel/code-frame": "^7.12.13",
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"@types/stack-utils": "^2.0.0",
"chalk": "^4.0.0",
"graceful-fs": "^4.2.9",
"micromatch": "^4.0.4",
- "pretty-format": "^29.6.2",
+ "pretty-format": "^29.7.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.3"
},
@@ -38102,13 +37808,13 @@
}
},
"node_modules/jest-mock": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.6.2.tgz",
- "integrity": "sha512-hoSv3lb3byzdKfwqCuT6uTscan471GUECqgNYykg6ob0yiAw3zYc7OrPnI9Qv8Wwoa4lC7AZ9hyS4AiIx5U2zg==",
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz",
+ "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==",
"dependencies": {
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
- "jest-util": "^29.6.2"
+ "jest-util": "^29.7.0"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
@@ -38744,9 +38450,9 @@
}
},
"node_modules/jest-util": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz",
- "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==",
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz",
+ "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==",
"dependencies": {
"@jest/types": "^29.6.3",
"@types/node": "*",
@@ -39446,9 +39152,9 @@
}
},
"node_modules/joi": {
- "version": "17.10.2",
- "resolved": "https://registry.npmjs.org/joi/-/joi-17.10.2.tgz",
- "integrity": "sha512-hcVhjBxRNW/is3nNLdGLIjkgXetkeGc2wyhydhz8KumG23Aerk4HPjU5zaPAMRqXQFc0xNqXTC7+zQjxr0GlKA==",
+ "version": "17.11.0",
+ "resolved": "https://registry.npmjs.org/joi/-/joi-17.11.0.tgz",
+ "integrity": "sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==",
"dependencies": {
"@hapi/hoek": "^9.0.0",
"@hapi/topo": "^5.0.0",
@@ -39599,17 +39305,6 @@
"node": ">=8"
}
},
- "node_modules/jscodeshift/node_modules/rimraf": {
- "version": "2.6.3",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
- "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- }
- },
"node_modules/jscodeshift/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -39621,17 +39316,6 @@
"node": ">=8"
}
},
- "node_modules/jscodeshift/node_modules/temp": {
- "version": "0.8.4",
- "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz",
- "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==",
- "dependencies": {
- "rimraf": "~2.6.2"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
"node_modules/jsdoc-type-pratt-parser": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz",
@@ -40102,6 +39786,28 @@
"immediate": "~3.0.5"
}
},
+ "node_modules/lighthouse-logger": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz",
+ "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==",
+ "dependencies": {
+ "debug": "^2.6.9",
+ "marky": "^1.2.2"
+ }
+ },
+ "node_modules/lighthouse-logger/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/lighthouse-logger/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
"node_modules/lightningcss": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.19.0.tgz",
@@ -40731,9 +40437,9 @@
}
},
"node_modules/lottie-react-native": {
- "version": "6.4.0",
- "resolved": "https://registry.npmjs.org/lottie-react-native/-/lottie-react-native-6.4.0.tgz",
- "integrity": "sha512-wFO/gLPN1KliyznBa8OtYWkc9Vn9OEmIg1/b1536KANFtGaFAeoAGhijVxYKF3UPKJgjJYFmqg0W//FVrSXj+g==",
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/lottie-react-native/-/lottie-react-native-6.4.1.tgz",
+ "integrity": "sha512-DPsUPSxLc3ZffeRQ/AtKtcUl4PzmJEEPt965tNpWSE4vhDkoGFxRe0TPZ45xX8/3HbGsUl48aMdLlAu28MEDsQ==",
"peerDependencies": {
"@dotlottie/react-player": "^1.6.1",
"@lottiefiles/react-lottie-player": "^3.5.3",
@@ -40995,6 +40701,11 @@
"react": ">= 0.14.0"
}
},
+ "node_modules/marky": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.5.tgz",
+ "integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q=="
+ },
"node_modules/matcher": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",
@@ -41989,10 +41700,9 @@
}
},
"node_modules/metro": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro/-/metro-0.76.8.tgz",
- "integrity": "sha512-oQA3gLzrrYv3qKtuWArMgHPbHu8odZOD9AoavrqSFllkPgOtmkBvNNDLCELqv5SjBfqjISNffypg+5UGG3y0pg==",
- "dev": true,
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro/-/metro-0.80.3.tgz",
+ "integrity": "sha512-7u6HjWVQR7wA/HbxzB0n6iQ0GI9s/fr49N++dZQ41BcrcFxrguIGaRe4W8VI5DtYifCVCjXDIFw6e9+MAccx/Q==",
"dependencies": {
"@babel/code-frame": "^7.0.0",
"@babel/core": "^7.20.0",
@@ -42002,7 +41712,6 @@
"@babel/traverse": "^7.20.0",
"@babel/types": "^7.20.0",
"accepts": "^1.3.7",
- "async": "^3.2.2",
"chalk": "^4.0.0",
"ci-info": "^2.0.0",
"connect": "^3.6.5",
@@ -42010,28 +41719,25 @@
"denodeify": "^1.2.1",
"error-stack-parser": "^2.0.6",
"graceful-fs": "^4.2.4",
- "hermes-parser": "0.12.0",
+ "hermes-parser": "0.18.2",
"image-size": "^1.0.2",
"invariant": "^2.2.4",
- "jest-worker": "^27.2.0",
+ "jest-worker": "^29.6.3",
"jsc-safe-url": "^0.2.2",
"lodash.throttle": "^4.1.1",
- "metro-babel-transformer": "0.76.8",
- "metro-cache": "0.76.8",
- "metro-cache-key": "0.76.8",
- "metro-config": "0.76.8",
- "metro-core": "0.76.8",
- "metro-file-map": "0.76.8",
- "metro-inspector-proxy": "0.76.8",
- "metro-minify-terser": "0.76.8",
- "metro-minify-uglify": "0.76.8",
- "metro-react-native-babel-preset": "0.76.8",
- "metro-resolver": "0.76.8",
- "metro-runtime": "0.76.8",
- "metro-source-map": "0.76.8",
- "metro-symbolicate": "0.76.8",
- "metro-transform-plugins": "0.76.8",
- "metro-transform-worker": "0.76.8",
+ "metro-babel-transformer": "0.80.3",
+ "metro-cache": "0.80.3",
+ "metro-cache-key": "0.80.3",
+ "metro-config": "0.80.3",
+ "metro-core": "0.80.3",
+ "metro-file-map": "0.80.3",
+ "metro-minify-terser": "0.80.3",
+ "metro-resolver": "0.80.3",
+ "metro-runtime": "0.80.3",
+ "metro-source-map": "0.80.3",
+ "metro-symbolicate": "0.80.3",
+ "metro-transform-plugins": "0.80.3",
+ "metro-transform-worker": "0.80.3",
"mime-types": "^2.1.27",
"node-fetch": "^2.2.0",
"nullthrows": "^1.1.1",
@@ -42047,68 +41753,76 @@
"metro": "src/cli.js"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/metro-babel-transformer": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.76.8.tgz",
- "integrity": "sha512-Hh6PW34Ug/nShlBGxkwQJSgPGAzSJ9FwQXhUImkzdsDgVu6zj5bx258J8cJVSandjNoQ8nbaHK6CaHlnbZKbyA==",
- "dev": true,
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.80.3.tgz",
+ "integrity": "sha512-Si1GO9fhiLi3DfHseFDaZcU+Y6iYHx54rszILnBIx80aas3pRZpL3z/UsEZ7coTQZTFsblt2QDIE+Izxlq4mwQ==",
"dependencies": {
"@babel/core": "^7.20.0",
- "hermes-parser": "0.12.0",
+ "hermes-parser": "0.18.2",
"nullthrows": "^1.1.1"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
+ }
+ },
+ "node_modules/metro-babel-transformer/node_modules/hermes-estree": {
+ "version": "0.18.2",
+ "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.18.2.tgz",
+ "integrity": "sha512-KoLsoWXJ5o81nit1wSyEZnWUGy9cBna9iYMZBR7skKh7okYAYKqQ9/OczwpMHn/cH0hKDyblulGsJ7FknlfVxQ=="
+ },
+ "node_modules/metro-babel-transformer/node_modules/hermes-parser": {
+ "version": "0.18.2",
+ "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.18.2.tgz",
+ "integrity": "sha512-1eQfvib+VPpgBZ2zYKQhpuOjw1tH+Emuib6QmjkJWJMhyjM8xnXMvA+76o9LhF0zOAJDZgPfQhg43cyXEyl5Ew==",
+ "dependencies": {
+ "hermes-estree": "0.18.2"
}
},
"node_modules/metro-cache": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.76.8.tgz",
- "integrity": "sha512-QBJSJIVNH7Hc/Yo6br/U/qQDUpiUdRgZ2ZBJmvAbmAKp2XDzsapnMwK/3BGj8JNWJF7OLrqrYHsRsukSbUBpvQ==",
- "dev": true,
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.80.3.tgz",
+ "integrity": "sha512-7gHcOIXdAHCBzsovF4b+VgcfIZtCpCIFiT2zx9amU58xrmkx+PRIl1KZDIUfRBbGrO9HJtZxH7lr7/hoiLIUWA==",
"dependencies": {
- "metro-core": "0.76.8",
+ "metro-core": "0.80.3",
"rimraf": "^3.0.2"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/metro-cache-key": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.76.8.tgz",
- "integrity": "sha512-buKQ5xentPig9G6T37Ww/R/bC+/V1MA5xU/D8zjnhlelsrPG6w6LtHUS61ID3zZcMZqYaELWk5UIadIdDsaaLw==",
- "dev": true,
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.80.3.tgz",
+ "integrity": "sha512-WNrtDpbhtW2Yqjp1t0WxJhKNR/Zbo1LZ4WvHsdv/PraAs2mr+SaM5bbiptBSKOOGJkV/FIQveW5riZi53JnCbw==",
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/metro-config": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.76.8.tgz",
- "integrity": "sha512-SL1lfKB0qGHALcAk2zBqVgQZpazDYvYFGwCK1ikz0S6Y/CM2i2/HwuZN31kpX6z3mqjv/6KvlzaKoTb1otuSAA==",
- "dev": true,
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.80.3.tgz",
+ "integrity": "sha512-cE7KPT1Usdrd2nLEVpzukKWmeBU1PufHPkuD9BjjtoABbzdj35gMLDnK+mhjSq9km2vF2QEPtE0M+WKvq9pXfQ==",
"dependencies": {
"connect": "^3.6.5",
"cosmiconfig": "^5.0.5",
- "jest-validate": "^29.2.1",
- "metro": "0.76.8",
- "metro-cache": "0.76.8",
- "metro-core": "0.76.8",
- "metro-runtime": "0.76.8"
+ "jest-validate": "^29.6.3",
+ "metro": "0.80.3",
+ "metro-cache": "0.80.3",
+ "metro-core": "0.80.3",
+ "metro-runtime": "0.80.3"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/metro-config/node_modules/cosmiconfig": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
"integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
- "dev": true,
"dependencies": {
"import-fresh": "^2.0.0",
"is-directory": "^0.3.1",
@@ -42123,7 +41837,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
"integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==",
- "dev": true,
"dependencies": {
"caller-path": "^2.0.0",
"resolve-from": "^3.0.0"
@@ -42136,7 +41849,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
"integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
- "dev": true,
"dependencies": {
"error-ex": "^1.3.1",
"json-parse-better-errors": "^1.0.1"
@@ -42149,129 +41861,49 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
"integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==",
- "dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/metro-core": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.76.8.tgz",
- "integrity": "sha512-sl2QLFI3d1b1XUUGxwzw/KbaXXU/bvFYrSKz6Sg19AdYGWFyzsgZ1VISRIDf+HWm4R/TJXluhWMEkEtZuqi3qA==",
- "dev": true,
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.80.3.tgz",
+ "integrity": "sha512-X2ZfAvR55TdD/Rv9i4gYVI68JpRPHcpKpkr6IVtidFPoNjf4Fodh1qH7gEAJUnO5FL3a1JyPffbW6eFaXPxkFw==",
"dependencies": {
"lodash.throttle": "^4.1.1",
- "metro-resolver": "0.76.8"
+ "metro-resolver": "0.80.3"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/metro-file-map": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.76.8.tgz",
- "integrity": "sha512-A/xP1YNEVwO1SUV9/YYo6/Y1MmzhL4ZnVgcJC3VmHp/BYVOXVStzgVbWv2wILe56IIMkfXU+jpXrGKKYhFyHVw==",
- "dev": true,
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.80.3.tgz",
+ "integrity": "sha512-4qu1ABPZRvboGGB8Q2RlQ26kZRWRCMDiktgCCrX/57V6cnWgdbdTrpnsgmU3i0Q7iiw+FevOGlfD4HqdauQ59g==",
"dependencies": {
"anymatch": "^3.0.3",
"debug": "^2.2.0",
"fb-watchman": "^2.0.0",
"graceful-fs": "^4.2.4",
"invariant": "^2.2.4",
- "jest-regex-util": "^27.0.6",
- "jest-util": "^27.2.0",
- "jest-worker": "^27.2.0",
+ "jest-worker": "^29.6.3",
"micromatch": "^4.0.4",
"node-abort-controller": "^3.1.1",
"nullthrows": "^1.1.1",
"walker": "^1.0.7"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
},
"optionalDependencies": {
"fsevents": "^2.3.2"
}
},
- "node_modules/metro-file-map/node_modules/@jest/types": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz",
- "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==",
- "dev": true,
- "dependencies": {
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^16.0.0",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
- }
- },
- "node_modules/metro-file-map/node_modules/@types/yargs": {
- "version": "16.0.6",
- "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.6.tgz",
- "integrity": "sha512-oTP7/Q13GSPrgcwEwdlnkoZSQ1Hg9THe644qq8PG6hhJzjZ3qj1JjEFPIwWV/IXVs5XGIVqtkNOS9kh63WIJ+A==",
- "dev": true,
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
- "node_modules/metro-file-map/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/metro-file-map/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/metro-file-map/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/metro-file-map/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
"node_modules/metro-file-map/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
"dependencies": {
"ms": "2.0.0"
}
@@ -42280,217 +41912,60 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
"engines": {
"node": ">=8"
}
},
- "node_modules/metro-file-map/node_modules/jest-regex-util": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz",
- "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==",
- "dev": true,
- "engines": {
- "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
- }
- },
- "node_modules/metro-file-map/node_modules/jest-util": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz",
- "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==",
- "dev": true,
- "dependencies": {
- "@jest/types": "^27.5.1",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "ci-info": "^3.2.0",
- "graceful-fs": "^4.2.9",
- "picomatch": "^2.2.3"
- },
- "engines": {
- "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
- }
- },
"node_modules/metro-file-map/node_modules/jest-worker": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
- "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
- "dev": true,
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz",
+ "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==",
"dependencies": {
"@types/node": "*",
+ "jest-util": "^29.7.0",
"merge-stream": "^2.0.0",
"supports-color": "^8.0.0"
},
"engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/metro-file-map/node_modules/jest-worker/node_modules/supports-color": {
- "version": "8.1.1",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
- "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/supports-color?sponsor=1"
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/metro-file-map/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
- "dev": true
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/metro-file-map/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"dependencies": {
"has-flag": "^4.0.0"
},
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/metro-inspector-proxy": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.76.8.tgz",
- "integrity": "sha512-Us5o5UEd4Smgn1+TfHX4LvVPoWVo9VsVMn4Ldbk0g5CQx3Gu0ygc/ei2AKPGTwsOZmKxJeACj7yMH2kgxQP/iw==",
- "dev": true,
- "dependencies": {
- "connect": "^3.6.5",
- "debug": "^2.2.0",
- "node-fetch": "^2.2.0",
- "ws": "^7.5.1",
- "yargs": "^17.6.2"
- },
- "bin": {
- "metro-inspector-proxy": "src/cli.js"
- },
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/metro-inspector-proxy/node_modules/cliui": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
- "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
- "dev": true,
- "dependencies": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.1",
- "wrap-ansi": "^7.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/metro-inspector-proxy/node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
- "dependencies": {
- "ms": "2.0.0"
- }
- },
- "node_modules/metro-inspector-proxy/node_modules/ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
- "dev": true
- },
- "node_modules/metro-inspector-proxy/node_modules/ws": {
- "version": "7.5.9",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
- "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
- "dev": true,
- "engines": {
- "node": ">=8.3.0"
- },
- "peerDependencies": {
- "bufferutil": "^4.0.1",
- "utf-8-validate": "^5.0.2"
- },
- "peerDependenciesMeta": {
- "bufferutil": {
- "optional": true
- },
- "utf-8-validate": {
- "optional": true
- }
- }
- },
- "node_modules/metro-inspector-proxy/node_modules/y18n": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
- "dev": true,
"engines": {
"node": ">=10"
- }
- },
- "node_modules/metro-inspector-proxy/node_modules/yargs": {
- "version": "17.7.2",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
- "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
- "dev": true,
- "dependencies": {
- "cliui": "^8.0.1",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "require-directory": "^2.1.1",
- "string-width": "^4.2.3",
- "y18n": "^5.0.5",
- "yargs-parser": "^21.1.1"
},
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/metro-inspector-proxy/node_modules/yargs-parser": {
- "version": "21.1.1",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
- "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
- "dev": true,
- "engines": {
- "node": ">=12"
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/metro-minify-terser": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.76.8.tgz",
- "integrity": "sha512-Orbvg18qXHCrSj1KbaeSDVYRy/gkro2PC7Fy2tDSH1c9RB4aH8tuMOIXnKJE+1SXxBtjWmQ5Yirwkth2DyyEZA==",
- "dev": true,
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.80.3.tgz",
+ "integrity": "sha512-gVFwoL86emFoYbI2DZKk1Ved2CklYv//huWriF0UpLJHmVEO9ii2ajTx3aIxgSeuxFLPJhdp8RgUB2EDCooaJw==",
"dependencies": {
"terser": "^5.15.0"
},
"engines": {
- "node": ">=16"
- }
- },
- "node_modules/metro-minify-uglify": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.76.8.tgz",
- "integrity": "sha512-6l8/bEvtVaTSuhG1FqS0+Mc8lZ3Bl4RI8SeRIifVLC21eeSDp4CEBUWSGjpFyUDfi6R5dXzYaFnSgMNyfxADiQ==",
- "dev": true,
- "dependencies": {
- "uglify-es": "^3.1.9"
- },
- "engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/metro-react-native-babel-preset": {
"version": "0.76.8",
"resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.76.8.tgz",
"integrity": "sha512-Ptza08GgqzxEdK8apYsjTx2S8WDUlS2ilBlu9DR1CUcHmg4g3kOkFylZroogVAUKtpYQNYwAvdsjmrSdDNtiAg==",
+ "dev": true,
+ "peer": true,
"dependencies": {
"@babel/core": "^7.20.0",
"@babel/plugin-proposal-async-generator-functions": "^7.0.0",
@@ -42541,75 +42016,48 @@
},
"node_modules/metro-react-native-babel-preset/node_modules/react-refresh": {
"version": "0.4.3",
+ "dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
},
- "node_modules/metro-react-native-babel-transformer": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.76.8.tgz",
- "integrity": "sha512-3h+LfS1WG1PAzhq8QF0kfXjxuXetbY/lgz8vYMQhgrMMp17WM1DNJD0gjx8tOGYbpbBC1qesJ45KMS4o5TA73A==",
- "dev": true,
- "dependencies": {
- "@babel/core": "^7.20.0",
- "babel-preset-fbjs": "^3.4.0",
- "hermes-parser": "0.12.0",
- "metro-react-native-babel-preset": "0.76.8",
- "nullthrows": "^1.1.1"
- },
- "engines": {
- "node": ">=16"
- },
- "peerDependencies": {
- "@babel/core": "*"
- }
- },
"node_modules/metro-resolver": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.76.8.tgz",
- "integrity": "sha512-KccOqc10vrzS7ZhG2NSnL2dh3uVydarB7nOhjreQ7C4zyWuiW9XpLC4h47KtGQv3Rnv/NDLJYeDqaJ4/+140HQ==",
- "dev": true,
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.80.3.tgz",
+ "integrity": "sha512-zwa0i32rj/TI3NivcvMXHJwTG2gUgo2dXdcnAJlhEKKQvyN+7AfhNdQSlDdDqMQmU7FaLRdeWORnQJbYCrprQQ==",
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/metro-runtime": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.76.8.tgz",
- "integrity": "sha512-XKahvB+iuYJSCr3QqCpROli4B4zASAYpkK+j3a0CJmokxCDNbgyI4Fp88uIL6rNaZfN0Mv35S0b99SdFXIfHjg==",
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.80.3.tgz",
+ "integrity": "sha512-16RKcwpxriNnPdE5eKWJu7/KLgxE+AaDAdYthoS6zbzjaOu7RiY2zPM1Elz175Rw//74kOwtKXgxTW8ADHB8SQ==",
"dependencies": {
- "@babel/runtime": "^7.0.0",
- "react-refresh": "^0.4.0"
+ "@babel/runtime": "^7.0.0"
},
"engines": {
- "node": ">=16"
- }
- },
- "node_modules/metro-runtime/node_modules/react-refresh": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz",
- "integrity": "sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA==",
- "engines": {
- "node": ">=0.10.0"
+ "node": ">=18"
}
},
"node_modules/metro-source-map": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.76.8.tgz",
- "integrity": "sha512-Hh0ncPsHPVf6wXQSqJqB3K9Zbudht4aUtNpNXYXSxH+pteWqGAXnjtPsRAnCsCWl38wL0jYF0rJDdMajUI3BDw==",
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.80.3.tgz",
+ "integrity": "sha512-5DYcOLPjDLx84ZCZ1i0DuWSPU7AY5G/7tR+u/WN6CZNxLyYEe3TwUBdIUgQj4HgZJl/zZ/7bGYJQOHd7ubuO0w==",
"dependencies": {
"@babel/traverse": "^7.20.0",
"@babel/types": "^7.20.0",
"invariant": "^2.2.4",
- "metro-symbolicate": "0.76.8",
+ "metro-symbolicate": "0.80.3",
"nullthrows": "^1.1.1",
- "ob1": "0.76.8",
+ "ob1": "0.80.3",
"source-map": "^0.5.6",
"vlq": "^1.0.0"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/metro-source-map/node_modules/source-map": {
@@ -42621,12 +42069,12 @@
}
},
"node_modules/metro-symbolicate": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.76.8.tgz",
- "integrity": "sha512-LrRL3uy2VkzrIXVlxoPtqb40J6Bf1mlPNmUQewipc3qfKKFgtPHBackqDy1YL0njDsWopCKcfGtFYLn0PTUn3w==",
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.80.3.tgz",
+ "integrity": "sha512-baIt8Ss2vTGbxolRTa5yg+tKVAIAB1OpwMzJ0FSUjLs+HDAzaOtSpGbNd3DPc+pzX8Gj/rdbDOA0wPuOhVsHKQ==",
"dependencies": {
"invariant": "^2.2.4",
- "metro-source-map": "0.76.8",
+ "metro-source-map": "0.80.3",
"nullthrows": "^1.1.1",
"source-map": "^0.5.6",
"through2": "^2.0.1",
@@ -42636,7 +42084,7 @@
"metro-symbolicate": "src/index.js"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/metro-symbolicate/node_modules/source-map": {
@@ -42648,10 +42096,9 @@
}
},
"node_modules/metro-transform-plugins": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.76.8.tgz",
- "integrity": "sha512-PlkGTQNqS51Bx4vuufSQCdSn2R2rt7korzngo+b5GCkeX5pjinPjnO2kNhQ8l+5bO0iUD/WZ9nsM2PGGKIkWFA==",
- "dev": true,
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.80.3.tgz",
+ "integrity": "sha512-/2hGGRdJPrNfB9lz8unukaqQpGpDhYwNM0Odfh37OVFjygMB30Ffd8neQ4FNqnHnFxhl5j8VTcopUg6QhygMGQ==",
"dependencies": {
"@babel/core": "^7.20.0",
"@babel/generator": "^7.20.0",
@@ -42660,37 +42107,34 @@
"nullthrows": "^1.1.1"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/metro-transform-worker": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.76.8.tgz",
- "integrity": "sha512-mE1fxVAnJKmwwJyDtThildxxos9+DGs9+vTrx2ktSFMEVTtXS/bIv2W6hux1pqivqAfyJpTeACXHk5u2DgGvIQ==",
- "dev": true,
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.80.3.tgz",
+ "integrity": "sha512-10ZwMDuSWyHwqNnZ50baNtHNuHhOnqThbTOgv03PsrmPHWmSv4/rrmm7711tEyLUxptY3A1hEgJ+LKYyOIQiUA==",
"dependencies": {
"@babel/core": "^7.20.0",
"@babel/generator": "^7.20.0",
"@babel/parser": "^7.20.0",
"@babel/types": "^7.20.0",
- "babel-preset-fbjs": "^3.4.0",
- "metro": "0.76.8",
- "metro-babel-transformer": "0.76.8",
- "metro-cache": "0.76.8",
- "metro-cache-key": "0.76.8",
- "metro-source-map": "0.76.8",
- "metro-transform-plugins": "0.76.8",
+ "metro": "0.80.3",
+ "metro-babel-transformer": "0.80.3",
+ "metro-cache": "0.80.3",
+ "metro-cache-key": "0.80.3",
+ "metro-source-map": "0.80.3",
+ "metro-transform-plugins": "0.80.3",
"nullthrows": "^1.1.1"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/metro/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
@@ -42705,7 +42149,6 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -42720,14 +42163,12 @@
"node_modules/metro/node_modules/ci-info": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
- "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
- "dev": true
+ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="
},
"node_modules/metro/node_modules/cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
- "dev": true,
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
@@ -42741,7 +42182,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
@@ -42752,14 +42192,12 @@
"node_modules/metro/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/metro/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
"dependencies": {
"ms": "2.0.0"
}
@@ -42768,30 +42206,41 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
"engines": {
"node": ">=8"
}
},
+ "node_modules/metro/node_modules/hermes-estree": {
+ "version": "0.18.2",
+ "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.18.2.tgz",
+ "integrity": "sha512-KoLsoWXJ5o81nit1wSyEZnWUGy9cBna9iYMZBR7skKh7okYAYKqQ9/OczwpMHn/cH0hKDyblulGsJ7FknlfVxQ=="
+ },
+ "node_modules/metro/node_modules/hermes-parser": {
+ "version": "0.18.2",
+ "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.18.2.tgz",
+ "integrity": "sha512-1eQfvib+VPpgBZ2zYKQhpuOjw1tH+Emuib6QmjkJWJMhyjM8xnXMvA+76o9LhF0zOAJDZgPfQhg43cyXEyl5Ew==",
+ "dependencies": {
+ "hermes-estree": "0.18.2"
+ }
+ },
"node_modules/metro/node_modules/jest-worker": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
- "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
- "dev": true,
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz",
+ "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==",
"dependencies": {
"@types/node": "*",
+ "jest-util": "^29.7.0",
"merge-stream": "^2.0.0",
"supports-color": "^8.0.0"
},
"engines": {
- "node": ">= 10.13.0"
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/metro/node_modules/jest-worker/node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
- "dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -42805,14 +42254,12 @@
"node_modules/metro/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
- "dev": true
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/metro/node_modules/serialize-error": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz",
"integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -42821,7 +42268,6 @@
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -42830,7 +42276,6 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -42842,7 +42287,6 @@
"version": "7.5.9",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
- "dev": true,
"engines": {
"node": ">=8.3.0"
},
@@ -42863,7 +42307,6 @@
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
- "dev": true,
"engines": {
"node": ">=10"
}
@@ -42872,7 +42315,6 @@
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
- "dev": true,
"dependencies": {
"cliui": "^8.0.1",
"escalade": "^3.1.1",
@@ -42890,7 +42332,6 @@
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
- "dev": true,
"engines": {
"node": ">=12"
}
@@ -44076,7 +43517,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz",
"integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
@@ -44185,9 +43625,9 @@
"optional": true
},
"node_modules/nanoid": {
- "version": "3.3.6",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
- "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
+ "version": "3.3.7",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
+ "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
"funding": [
{
"type": "github",
@@ -44605,11 +44045,11 @@
"license": "MIT"
},
"node_modules/ob1": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.76.8.tgz",
- "integrity": "sha512-dlBkJJV5M/msj9KYA9upc+nUWVwuOFFTbu28X6kZeGwcuW+JxaHSBZ70SYQnk5M+j5JbNLR6yKHmgW4M5E7X5g==",
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.80.3.tgz",
+ "integrity": "sha512-lKJ/Wp6eSyYKYKYds1lgiDRtD2j9nNhrhx4hwegxYXTBkWz4dqermZV+Bq0iw0SszUIb+fC+btNSXwc4AG1lBQ==",
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/object-assign": {
@@ -45745,7 +45185,6 @@
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz",
"integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==",
- "dev": true,
"dependencies": {
"lru-cache": "^9.1.1 || ^10.0.0",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
@@ -45761,7 +45200,6 @@
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz",
"integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==",
- "dev": true,
"engines": {
"node": "14 || >=16.14"
}
@@ -45770,7 +45208,6 @@
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz",
"integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==",
- "dev": true,
"engines": {
"node": ">=16 || 14 >=14.17"
}
@@ -45948,6 +45385,7 @@
},
"node_modules/pkg-up": {
"version": "3.1.0",
+ "dev": true,
"license": "MIT",
"dependencies": {
"find-up": "^3.0.0"
@@ -45958,6 +45396,7 @@
},
"node_modules/pkg-up/node_modules/find-up": {
"version": "3.0.0",
+ "dev": true,
"license": "MIT",
"dependencies": {
"locate-path": "^3.0.0"
@@ -45968,6 +45407,7 @@
},
"node_modules/pkg-up/node_modules/locate-path": {
"version": "3.0.0",
+ "dev": true,
"license": "MIT",
"dependencies": {
"p-locate": "^3.0.0",
@@ -45979,6 +45419,7 @@
},
"node_modules/pkg-up/node_modules/p-limit": {
"version": "2.3.0",
+ "dev": true,
"license": "MIT",
"dependencies": {
"p-try": "^2.0.0"
@@ -45992,6 +45433,7 @@
},
"node_modules/pkg-up/node_modules/p-locate": {
"version": "3.0.0",
+ "dev": true,
"license": "MIT",
"dependencies": {
"p-limit": "^2.0.0"
@@ -46321,9 +45763,9 @@
}
},
"node_modules/pretty-format": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz",
- "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==",
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
+ "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
"dependencies": {
"@jest/schemas": "^29.6.3",
"ansi-styles": "^5.0.0",
@@ -47240,43 +46682,44 @@
}
},
"node_modules/react-native": {
- "version": "0.72.4",
- "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.72.4.tgz",
- "integrity": "sha512-+vrObi0wZR+NeqL09KihAAdVlQ9IdplwznJWtYrjnQ4UbCW6rkzZJebRsugwUneSOKNFaHFEo1uKU89HsgtYBg==",
- "dependencies": {
- "@jest/create-cache-key-function": "^29.2.1",
- "@react-native-community/cli": "11.3.6",
- "@react-native-community/cli-platform-android": "11.3.6",
- "@react-native-community/cli-platform-ios": "11.3.6",
- "@react-native/assets-registry": "^0.72.0",
- "@react-native/codegen": "^0.72.6",
- "@react-native/gradle-plugin": "^0.72.11",
- "@react-native/js-polyfills": "^0.72.1",
- "@react-native/normalize-colors": "^0.72.0",
- "@react-native/virtualized-lists": "^0.72.8",
+ "version": "0.73.2",
+ "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.73.2.tgz",
+ "integrity": "sha512-7zj9tcUYpJUBdOdXY6cM8RcXYWkyql4kMyGZflW99E5EuFPoC7Ti+ZQSl7LP9ZPzGD0vMfslwyDW0I4tPWUCFw==",
+ "dependencies": {
+ "@jest/create-cache-key-function": "^29.6.3",
+ "@react-native-community/cli": "12.3.0",
+ "@react-native-community/cli-platform-android": "12.3.0",
+ "@react-native-community/cli-platform-ios": "12.3.0",
+ "@react-native/assets-registry": "0.73.1",
+ "@react-native/codegen": "0.73.2",
+ "@react-native/community-cli-plugin": "0.73.12",
+ "@react-native/gradle-plugin": "0.73.4",
+ "@react-native/js-polyfills": "0.73.1",
+ "@react-native/normalize-colors": "0.73.2",
+ "@react-native/virtualized-lists": "0.73.4",
"abort-controller": "^3.0.0",
"anser": "^1.4.9",
- "base64-js": "^1.1.2",
- "deprecated-react-native-prop-types": "4.1.0",
+ "ansi-regex": "^5.0.0",
+ "base64-js": "^1.5.1",
+ "deprecated-react-native-prop-types": "^5.0.0",
"event-target-shim": "^5.0.1",
- "flow-enums-runtime": "^0.0.5",
+ "flow-enums-runtime": "^0.0.6",
"invariant": "^2.2.4",
- "jest-environment-node": "^29.2.1",
+ "jest-environment-node": "^29.6.3",
"jsc-android": "^250231.0.0",
"memoize-one": "^5.0.0",
- "metro-runtime": "0.76.8",
- "metro-source-map": "0.76.8",
+ "metro-runtime": "^0.80.3",
+ "metro-source-map": "^0.80.3",
"mkdirp": "^0.5.1",
"nullthrows": "^1.1.1",
"pretty-format": "^26.5.2",
"promise": "^8.3.0",
- "react-devtools-core": "^4.27.2",
- "react-refresh": "^0.4.0",
+ "react-devtools-core": "^4.27.7",
+ "react-refresh": "^0.14.0",
"react-shallow-renderer": "^16.15.0",
"regenerator-runtime": "^0.13.2",
"scheduler": "0.24.0-canary-efb381bbf-20230505",
"stacktrace-parser": "^0.1.10",
- "use-sync-external-store": "^1.0.0",
"whatwg-fetch": "^3.0.0",
"ws": "^6.2.2",
"yargs": "^17.6.2"
@@ -47285,7 +46728,7 @@
"react-native": "cli.js"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
},
"peerDependencies": {
"react": "18.2.0"
@@ -47429,6 +46872,7 @@
"integrity": "sha512-M784S/qPuN/HqjdvXg98HIDmfm0sF8mACc56YNg87nzEF90zKSKp0XyOE83SEW+UJX2Gq/rf9BvM2GZeXlrhnQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-native": ">0.62.0"
@@ -47453,9 +46897,9 @@
}
},
"node_modules/react-native-gesture-handler": {
- "version": "2.12.0",
- "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.12.0.tgz",
- "integrity": "sha512-rr+XwVzXAVpY8co25ukvyI38fKCxTQjz7WajeZktl8qUPdh1twnSExgpT47DqDi4n+m+OiJPAnHfZOkqqAQMOg==",
+ "version": "2.14.0",
+ "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.14.0.tgz",
+ "integrity": "sha512-cOmdaqbpzjWrOLUpX3hdSjsMby5wq3PIEdMq7okJeg9DmCzanysHSrktw1cXWNc/B5MAgxAn9J7Km0/4UIqKAQ==",
"dependencies": {
"@egjs/hammerjs": "^2.0.17",
"hoist-non-react-statics": "^3.3.0",
@@ -47590,17 +47034,17 @@
}
},
"node_modules/react-native-onyx": {
- "version": "1.0.118",
- "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.118.tgz",
- "integrity": "sha512-w54jO+Bpu1ElHsrxZXIIpcBqNkrUvuVCQmwWdfOW5LvO4UwsPSwmMxzExbUZ4ip+7CROmm10IgXFaAoyfeYSVQ==",
+ "version": "1.0.126",
+ "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.126.tgz",
+ "integrity": "sha512-tUJI1mQaWXLfyBFYQQWM6mm9GiCqIXGvjbqJkH1fLY3OqbGW6DyH4CxC+qJrqfi4bKZgZHp5xlBHhkPV4pKK2A==",
"dependencies": {
"ascii-table": "0.0.9",
"fast-equals": "^4.0.3",
"underscore": "^1.13.6"
},
"engines": {
- "node": ">=16.15.1 <=20.9.0",
- "npm": ">=8.11.0 <=10.1.0"
+ "node": "20.9.0",
+ "npm": "10.1.0"
},
"peerDependencies": {
"idb-keyval": "^6.2.1",
@@ -47626,18 +47070,18 @@
}
},
"node_modules/react-native-pager-view": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.2.0.tgz",
- "integrity": "sha512-pf9OnL/Tkr+5s4Gjmsn7xh91PtJLDa6qxYa/bmtUhd/+s4cQdWQ8DIFoOFghwZIHHHwVdWtoXkp6HtpjN+r20g==",
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.2.2.tgz",
+ "integrity": "sha512-MLkJB7iP6v0Hd4/B4/R/gLCSE+YBtjxG/vHZYBDU+fI3U7HBYgKAg4o6ad8HxbKVcWWyRDNeeVRGISw1MUjlHw==",
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-pdf": {
- "version": "6.7.3",
- "resolved": "https://registry.npmjs.org/react-native-pdf/-/react-native-pdf-6.7.3.tgz",
- "integrity": "sha512-bK1fVkj18kBA5YlRFNJ3/vJ1bEX3FDHyAPY6ArtIdVs+vv0HzcK5WH9LSd2bxUsEMIyY9CSjP4j8BcxNXTiQkQ==",
+ "version": "6.7.4",
+ "resolved": "https://registry.npmjs.org/react-native-pdf/-/react-native-pdf-6.7.4.tgz",
+ "integrity": "sha512-sBeNcsrTRnLjmiU9Wx7Uk0K2kPSQtKIIG+FECdrEG16TOdtmQ3iqqEwt0dmy0pJegpg07uES5BXqiKsKkRUIFw==",
"dependencies": {
"crypto-js": "4.2.0",
"deprecated-react-native-prop-types": "^2.3.0"
@@ -47804,19 +47248,18 @@
"license": "MIT"
},
"node_modules/react-native-safe-area-context": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.4.1.tgz",
- "integrity": "sha512-N9XTjiuD73ZpVlejHrUWIFZc+6Z14co1K/p1IFMkImU7+avD69F3y+lhkqA2hN/+vljdZrBSiOwXPkuo43nFQA==",
- "license": "MIT",
+ "version": "4.7.4",
+ "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.7.4.tgz",
+ "integrity": "sha512-3LR3DCq9pdzlbq6vsHGWBFehXAKDh2Ljug6jWhLWs1QFuJHM6AS2+mH2JfKlB2LqiSFZOBcZfHQFz0sGaA3uqg==",
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-screens": {
- "version": "3.21.0",
- "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.21.0.tgz",
- "integrity": "sha512-SybzBhceTN2LUfzvEQxpZ9SchlFgEdsR/+YOKcpIhKg2BdRObdIyQsRoJBvduZ55lKbO9Gpyl3Ke8tngz3873g==",
+ "version": "3.29.0",
+ "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.29.0.tgz",
+ "integrity": "sha512-yB1GoAMamFAcYf4ku94uBPn0/ani9QG7NdI98beJ5cet2YFESYYzuEIuU+kt+CNRcO8qqKeugxlfgAa3HyTqlg==",
"dependencies": {
"react-freeze": "^1.0.0",
"warn-once": "^0.1.0"
@@ -47827,9 +47270,9 @@
}
},
"node_modules/react-native-svg": {
- "version": "13.14.0",
- "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-13.14.0.tgz",
- "integrity": "sha512-27ZnxUkHgWICimhuj6MuqBkISN53lVvgWJB7pIypjXysAyM+nqgQBPh4vXg+7MbqLBoYvR4PiBgKfwwGAqVxHg==",
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-14.0.0.tgz",
+ "integrity": "sha512-17W/gWXRUMS7p7PSHu/WyGkZUc1NzRTGxxXc0VqBLjzKSchyb0EmgsiWf9aKmfC6gmY0wcsmKZcGV41bCcNfBA==",
"dependencies": {
"css-select": "^5.1.0",
"css-tree": "^1.1.3"
@@ -47864,8 +47307,12 @@
}
},
"node_modules/react-native-view-shot": {
- "version": "3.6.0",
- "license": "MIT",
+ "version": "3.8.0",
+ "resolved": "https://registry.npmjs.org/react-native-view-shot/-/react-native-view-shot-3.8.0.tgz",
+ "integrity": "sha512-4cU8SOhMn3YQIrskh+5Q8VvVRxQOu8/s1M9NAL4z5BY1Rm0HXMWkQJ4N0XsZ42+Yca+y86ISF3LC5qdLPvPuiA==",
+ "dependencies": {
+ "html2canvas": "^1.4.1"
+ },
"peerDependencies": {
"react": "*",
"react-native": "*"
@@ -47913,8 +47360,9 @@
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
},
"node_modules/react-native-webview": {
- "version": "11.23.0",
- "license": "MIT",
+ "version": "13.6.3",
+ "resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-13.6.3.tgz",
+ "integrity": "sha512-IApO0JSj0uAWsBGKWagyfgDYoX29piiMYLmkHtRjKeL1rIVjLoR/bMe7KJ/0X47y86b//a6u3cYQtphyay+F2A==",
"dependencies": {
"escape-string-regexp": "2.0.0",
"invariant": "2.2.4"
@@ -47985,13 +47433,16 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/react-native/node_modules/deprecated-react-native-prop-types": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-4.1.0.tgz",
- "integrity": "sha512-WfepZHmRbbdTvhcolb8aOKEvQdcmTMn5tKLbqbXmkBvjFjRVWAYqsXk/DBsV8TZxws8SdGHLuHaJrHSQUPRdfw==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-5.0.0.tgz",
+ "integrity": "sha512-cIK8KYiiGVOFsKdPMmm1L3tA/Gl+JopXL6F5+C7x39MyPsQYnP57Im/D6bNUzcborD7fcMwiwZqcBdBXXZucYQ==",
"dependencies": {
- "@react-native/normalize-colors": "*",
- "invariant": "*",
- "prop-types": "*"
+ "@react-native/normalize-colors": "^0.73.0",
+ "invariant": "^2.2.4",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/react-native/node_modules/mkdirp": {
@@ -48033,9 +47484,9 @@
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
},
"node_modules/react-native/node_modules/react-refresh": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz",
- "integrity": "sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA==",
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
+ "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==",
"engines": {
"node": ">=0.10.0"
}
@@ -49867,6 +49318,7 @@
},
"node_modules/reselect": {
"version": "4.1.7",
+ "dev": true,
"license": "MIT"
},
"node_modules/resolve": {
@@ -49935,8 +49387,9 @@
"license": "MIT"
},
"node_modules/resolve.exports": {
- "version": "2.0.0",
- "license": "MIT",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz",
+ "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==",
"engines": {
"node": ">=10"
}
@@ -50302,8 +49755,7 @@
"node_modules/select": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
- "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==",
- "license": "MIT"
+ "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA=="
},
"node_modules/select-hose": {
"version": "2.0.0",
@@ -50578,6 +50030,11 @@
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"license": "ISC"
},
+ "node_modules/set-cookie-parser": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz",
+ "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ=="
+ },
"node_modules/set-value": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
@@ -51770,6 +51227,11 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/stream-slice": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/stream-slice/-/stream-slice-0.1.2.tgz",
+ "integrity": "sha512-QzQxpoacatkreL6jsxnVb7X5R/pGw9OUv2qWTYWnmLpg4NdN31snPy/f3TdQE1ZUXaThRvj1Zw4/OGg0ZkaLMA=="
+ },
"node_modules/strict-uri-encode": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
@@ -51819,7 +51281,6 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@@ -51881,14 +51342,15 @@
}
},
"node_modules/string.prototype.replaceall": {
- "version": "1.0.6",
- "license": "MIT",
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/string.prototype.replaceall/-/string.prototype.replaceall-1.0.8.tgz",
+ "integrity": "sha512-MmCXb9980obcnmbEd3guqVl6lXTxpP28zASfgAlAhlBMw5XehQeSKsdIWlAYtLxp/1GtALwex+2HyoIQtaLQwQ==",
"dependencies": {
"call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1",
- "get-intrinsic": "^1.1.1",
- "has-symbols": "^1.0.2",
+ "define-properties": "^1.2.0",
+ "es-abstract": "^1.22.1",
+ "get-intrinsic": "^1.2.1",
+ "has-symbols": "^1.0.3",
"is-regex": "^1.1.4"
},
"funding": {
@@ -51969,7 +51431,6 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
"dependencies": {
"ansi-regex": "^5.0.1"
},
@@ -51981,7 +51442,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
"engines": {
"node": ">=8"
}
@@ -52093,13 +51553,13 @@
"integrity": "sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA=="
},
"node_modules/sucrase": {
- "version": "3.34.0",
- "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz",
- "integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==",
+ "version": "3.35.0",
+ "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
+ "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.2",
"commander": "^4.0.0",
- "glob": "7.1.6",
+ "glob": "^10.3.10",
"lines-and-columns": "^1.1.6",
"mz": "^2.7.0",
"pirates": "^4.0.1",
@@ -52110,7 +51570,7 @@
"sucrase-node": "bin/sucrase-node"
},
"engines": {
- "node": ">=8"
+ "node": ">=16 || 14 >=14.17"
}
},
"node_modules/sucrase/node_modules/@jridgewell/gen-mapping": {
@@ -52126,6 +51586,14 @@
"node": ">=6.0.0"
}
},
+ "node_modules/sucrase/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
"node_modules/sucrase/node_modules/commander": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
@@ -52134,6 +51602,75 @@
"node": ">= 6"
}
},
+ "node_modules/sucrase/node_modules/foreground-child": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
+ "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==",
+ "dependencies": {
+ "cross-spawn": "^7.0.0",
+ "signal-exit": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/sucrase/node_modules/glob": {
+ "version": "10.3.10",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
+ "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==",
+ "dependencies": {
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^2.3.5",
+ "minimatch": "^9.0.1",
+ "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0",
+ "path-scurry": "^1.10.1"
+ },
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/sucrase/node_modules/minimatch": {
+ "version": "9.0.3",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+ "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/sucrase/node_modules/minipass": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz",
+ "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/sucrase/node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/sudo-prompt": {
"version": "9.2.1",
"resolved": "https://registry.npmjs.org/sudo-prompt/-/sudo-prompt-9.2.1.tgz",
@@ -52521,6 +52058,17 @@
"node": ">=0.10.0"
}
},
+ "node_modules/temp": {
+ "version": "0.8.4",
+ "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz",
+ "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==",
+ "dependencies": {
+ "rimraf": "~2.6.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/temp-dir": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz",
@@ -52553,6 +52101,17 @@
"node": ">=12"
}
},
+ "node_modules/temp/node_modules/rimraf": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+ "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ }
+ },
"node_modules/tempy": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/tempy/-/tempy-0.7.1.tgz",
@@ -52824,6 +52383,14 @@
"node": ">=8"
}
},
+ "node_modules/text-segmentation": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
+ "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
+ "dependencies": {
+ "utrie": "^1.0.2"
+ }
+ },
"node_modules/text-table": {
"version": "0.2.0",
"license": "MIT"
@@ -53199,9 +52766,12 @@
}
},
"node_modules/traverse": {
- "version": "0.6.7",
- "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz",
- "integrity": "sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==",
+ "version": "0.6.8",
+ "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.8.tgz",
+ "integrity": "sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==",
+ "engines": {
+ "node": ">= 0.4"
+ },
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@@ -53580,27 +53150,6 @@
"node": "*"
}
},
- "node_modules/uglify-es": {
- "version": "3.3.9",
- "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz",
- "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==",
- "deprecated": "support for ECMAScript is superseded by `uglify-js` as of v3.13.0",
- "dependencies": {
- "commander": "~2.13.0",
- "source-map": "~0.6.1"
- },
- "bin": {
- "uglifyjs": "bin/uglifyjs"
- },
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/uglify-es/node_modules/commander": {
- "version": "2.13.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz",
- "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA=="
- },
"node_modules/uglify-js": {
"version": "3.17.4",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
@@ -54238,14 +53787,6 @@
}
}
},
- "node_modules/use-sync-external-store": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
- "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
- "peerDependencies": {
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
- }
- },
"node_modules/utf8": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz",
@@ -54304,6 +53845,14 @@
"node": ">= 0.4.0"
}
},
+ "node_modules/utrie": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
+ "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
+ "dependencies": {
+ "base64-arraybuffer": "^1.0.2"
+ }
+ },
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
@@ -54862,6 +54411,29 @@
"defaults": "^1.0.3"
}
},
+ "node_modules/web-encoding": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz",
+ "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==",
+ "dependencies": {
+ "util": "^0.12.3"
+ },
+ "optionalDependencies": {
+ "@zxing/text-encoding": "0.9.0"
+ }
+ },
+ "node_modules/web-encoding/node_modules/util": {
+ "version": "0.12.5",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
+ "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "is-arguments": "^1.0.4",
+ "is-generator-function": "^1.0.7",
+ "is-typed-array": "^1.1.3",
+ "which-typed-array": "^1.1.2"
+ }
+ },
"node_modules/web-namespaces": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz",
@@ -55827,7 +55399,6 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
@@ -55844,7 +55415,6 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
@@ -55859,7 +55429,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
@@ -55870,8 +55439,7 @@
"node_modules/wrap-ansi-cjs/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/wrap-ansi/node_modules/ansi-styles": {
"version": "4.3.0",
@@ -56530,14 +56098,14 @@
}
},
"@babel/helper-create-class-features-plugin": {
- "version": "7.22.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.9.tgz",
- "integrity": "sha512-Pwyi89uO4YrGKxL/eNJ8lfEH55DnRloGPOseaA8NFNL6jAUnn+KccaISiFazCj5IolPPDjGSdzQzXVzODVRqUQ==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz",
+ "integrity": "sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==",
"requires": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-environment-visitor": "^7.22.5",
"@babel/helper-function-name": "^7.22.5",
- "@babel/helper-member-expression-to-functions": "^7.22.5",
+ "@babel/helper-member-expression-to-functions": "^7.22.15",
"@babel/helper-optimise-call-expression": "^7.22.5",
"@babel/helper-replace-supers": "^7.22.9",
"@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
@@ -56610,19 +56178,19 @@
}
},
"@babel/helper-member-expression-to-functions": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.5.tgz",
- "integrity": "sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz",
+ "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==",
"requires": {
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.23.0"
}
},
"@babel/helper-module-imports": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz",
- "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz",
+ "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==",
"requires": {
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.22.15"
}
},
"@babel/helper-module-transforms": {
@@ -56696,9 +56264,9 @@
}
},
"@babel/helper-string-parser": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
- "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw=="
+ "version": "7.23.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
+ "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ=="
},
"@babel/helper-validator-identifier": {
"version": "7.22.20",
@@ -56706,9 +56274,9 @@
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A=="
},
"@babel/helper-validator-option": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz",
- "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw=="
+ "version": "7.23.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz",
+ "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw=="
},
"@babel/helper-wrap-function": {
"version": "7.22.5",
@@ -56801,6 +56369,7 @@
},
"@babel/plugin-proposal-export-namespace-from": {
"version": "7.18.9",
+ "dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.18.9",
"@babel/plugin-syntax-export-namespace-from": "^7.8.3"
@@ -56987,9 +56556,9 @@
}
},
"@babel/plugin-syntax-jsx": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz",
- "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==",
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz",
+ "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==",
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -57208,9 +56777,9 @@
}
},
"@babel/plugin-transform-export-namespace-from": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.5.tgz",
- "integrity": "sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg==",
+ "version": "7.23.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz",
+ "integrity": "sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==",
"requires": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-export-namespace-from": "^7.8.3"
@@ -57398,9 +56967,9 @@
}
},
"@babel/plugin-transform-parameters": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz",
- "integrity": "sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg==",
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz",
+ "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==",
"requires": {
"@babel/helper-plugin-utils": "^7.22.5"
}
@@ -57415,12 +56984,12 @@
}
},
"@babel/plugin-transform-private-property-in-object": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.5.tgz",
- "integrity": "sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ==",
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.3.tgz",
+ "integrity": "sha512-a5m2oLNFyje2e/rGKjVfAELTVI5mbA0FeZpBnkOWWV7eSmKQ+T/XW0Vf+29ScLzSxX+rnsarvU0oie/4m6hkxA==",
"requires": {
"@babel/helper-annotate-as-pure": "^7.22.5",
- "@babel/helper-create-class-features-plugin": "^7.22.5",
+ "@babel/helper-create-class-features-plugin": "^7.22.15",
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/plugin-syntax-private-property-in-object": "^7.14.5"
}
@@ -57443,26 +57012,31 @@
}
},
"@babel/plugin-transform-react-display-name": {
- "version": "7.18.6",
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.23.3.tgz",
+ "integrity": "sha512-GnvhtVfA2OAtzdX58FJxU19rhoGeQzyVndw3GgtdECQvQFXPEZIOVULHVZGAYmOgmqjXpVpfocAbSjh99V/Fqw==",
"requires": {
- "@babel/helper-plugin-utils": "^7.18.6"
+ "@babel/helper-plugin-utils": "^7.22.5"
}
},
"@babel/plugin-transform-react-jsx": {
- "version": "7.18.10",
+ "version": "7.23.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz",
+ "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==",
"requires": {
- "@babel/helper-annotate-as-pure": "^7.18.6",
- "@babel/helper-module-imports": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.9",
- "@babel/plugin-syntax-jsx": "^7.18.6",
- "@babel/types": "^7.18.10"
+ "@babel/helper-annotate-as-pure": "^7.22.5",
+ "@babel/helper-module-imports": "^7.22.15",
+ "@babel/helper-plugin-utils": "^7.22.5",
+ "@babel/plugin-syntax-jsx": "^7.23.3",
+ "@babel/types": "^7.23.4"
}
},
"@babel/plugin-transform-react-jsx-development": {
- "version": "7.18.6",
- "dev": true,
+ "version": "7.22.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz",
+ "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==",
"requires": {
- "@babel/plugin-transform-react-jsx": "^7.18.6"
+ "@babel/plugin-transform-react-jsx": "^7.22.5"
}
},
"@babel/plugin-transform-react-jsx-self": {
@@ -57478,11 +57052,12 @@
}
},
"@babel/plugin-transform-react-pure-annotations": {
- "version": "7.18.6",
- "dev": true,
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.23.3.tgz",
+ "integrity": "sha512-qMFdSS+TUhB7Q/3HVPnEdYJDQIk57jkntAwSuz9xfSE4n+3I+vHYCli3HoHawN1Z3RfCz/y1zXA/JXjG6cVImQ==",
"requires": {
- "@babel/helper-annotate-as-pure": "^7.18.6",
- "@babel/helper-plugin-utils": "^7.18.6"
+ "@babel/helper-annotate-as-pure": "^7.22.5",
+ "@babel/helper-plugin-utils": "^7.22.5"
}
},
"@babel/plugin-transform-regenerator": {
@@ -57765,15 +57340,16 @@
}
},
"@babel/preset-react": {
- "version": "7.18.6",
- "dev": true,
+ "version": "7.23.3",
+ "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.23.3.tgz",
+ "integrity": "sha512-tbkHOS9axH6Ysf2OUEqoSZ6T3Fa2SrNH6WTWSPBboxKzdxNc9qOICeLXkNG0ZEwbQ1HY8liwOce4aN/Ceyuq6w==",
"requires": {
- "@babel/helper-plugin-utils": "^7.18.6",
- "@babel/helper-validator-option": "^7.18.6",
- "@babel/plugin-transform-react-display-name": "^7.18.6",
- "@babel/plugin-transform-react-jsx": "^7.18.6",
- "@babel/plugin-transform-react-jsx-development": "^7.18.6",
- "@babel/plugin-transform-react-pure-annotations": "^7.18.6"
+ "@babel/helper-plugin-utils": "^7.22.5",
+ "@babel/helper-validator-option": "^7.22.15",
+ "@babel/plugin-transform-react-display-name": "^7.23.3",
+ "@babel/plugin-transform-react-jsx": "^7.22.15",
+ "@babel/plugin-transform-react-jsx-development": "^7.22.5",
+ "@babel/plugin-transform-react-pure-annotations": "^7.23.3"
}
},
"@babel/preset-typescript": {
@@ -57846,11 +57422,11 @@
}
},
"@babel/types": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
- "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
+ "version": "7.23.6",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz",
+ "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==",
"requires": {
- "@babel/helper-string-parser": "^7.22.5",
+ "@babel/helper-string-parser": "^7.23.4",
"@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
}
@@ -58422,53 +57998,62 @@
}
},
"@expo/cli": {
- "version": "0.10.16",
- "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-0.10.16.tgz",
- "integrity": "sha512-EwgnRN5AMElg0JJjFLJTPk5hYkVXxnNMLIvZBiTfGoCq+rDw6u7Mg5l2Bbm/geSHOoplaHyPZ/Wr23FAuZWehA==",
+ "version": "0.16.5",
+ "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-0.16.5.tgz",
+ "integrity": "sha512-4SAAymmV97OeskbYbpiJ/HFSUHLIyYmP8RlZE0svH+A1Z2lsAbjm8G7t5dFt5WPZGHWuj0y/DzIT8eElqvwHEg==",
"requires": {
"@babel/runtime": "^7.20.0",
"@expo/code-signing-certificates": "0.0.5",
- "@expo/config": "~8.1.0",
- "@expo/config-plugins": "~7.2.0",
- "@expo/dev-server": "0.5.5",
+ "@expo/config": "~8.5.0",
+ "@expo/config-plugins": "~7.8.0",
"@expo/devcert": "^1.0.0",
- "@expo/env": "0.0.5",
+ "@expo/env": "~0.2.0",
+ "@expo/image-utils": "^0.4.0",
"@expo/json-file": "^8.2.37",
- "@expo/metro-config": "~0.10.0",
+ "@expo/metro-config": "~0.17.0",
"@expo/osascript": "^2.0.31",
- "@expo/package-manager": "~1.1.0",
- "@expo/plist": "^0.0.20",
- "@expo/prebuild-config": "6.2.6",
+ "@expo/package-manager": "^1.1.1",
+ "@expo/plist": "^0.1.0",
+ "@expo/prebuild-config": "6.7.2",
"@expo/rudder-sdk-node": "1.1.1",
+ "@expo/server": "^0.3.0",
"@expo/spawn-async": "1.5.0",
- "@expo/xcpretty": "^4.2.1",
+ "@expo/xcpretty": "^4.3.0",
+ "@react-native/dev-middleware": "^0.73.6",
"@urql/core": "2.3.6",
"@urql/exchange-retry": "0.3.0",
"accepts": "^1.3.8",
- "arg": "4.1.0",
+ "arg": "5.0.2",
"better-opn": "~3.0.2",
"bplist-parser": "^0.3.1",
"cacache": "^15.3.0",
"chalk": "^4.0.0",
"ci-info": "^3.3.0",
+ "connect": "^3.7.0",
"debug": "^4.3.4",
"env-editor": "^0.4.1",
+ "find-yarn-workspace-root": "~2.0.0",
"form-data": "^3.0.1",
"freeport-async": "2.0.0",
"fs-extra": "~8.1.0",
"getenv": "^1.0.0",
+ "glob": "^7.1.7",
"graphql": "15.8.0",
"graphql-tag": "^2.10.1",
"https-proxy-agent": "^5.0.1",
"internal-ip": "4.3.0",
+ "is-docker": "^2.0.0",
+ "is-wsl": "^2.1.1",
"js-yaml": "^3.13.1",
"json-schema-deref-sync": "^0.13.0",
- "md5-file": "^3.2.3",
+ "lodash.debounce": "^4.0.8",
"md5hex": "^1.0.0",
- "minipass": "3.1.6",
+ "minimatch": "^3.0.4",
+ "minipass": "3.3.6",
"node-fetch": "^2.6.7",
"node-forge": "^1.3.1",
"npm-package-arg": "^7.0.0",
+ "open": "^8.3.0",
"ora": "3.4.0",
"pretty-bytes": "5.6.0",
"progress": "2.0.3",
@@ -58476,12 +58061,15 @@
"qrcode-terminal": "0.11.0",
"require-from-string": "^2.0.2",
"requireg": "^0.2.2",
+ "resolve": "^1.22.2",
"resolve-from": "^5.0.0",
+ "resolve.exports": "^2.0.2",
"semver": "^7.5.3",
"send": "^0.18.0",
"slugify": "^1.3.4",
"structured-headers": "^0.4.1",
"tar": "^6.0.5",
+ "temp-dir": "^2.0.0",
"tempy": "^0.7.1",
"terminal-link": "^2.1.1",
"text-table": "^0.2.0",
@@ -58499,13 +58087,14 @@
}
},
"@expo/config-plugins": {
- "version": "7.2.5",
- "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.2.5.tgz",
- "integrity": "sha512-w+5ccu1IxBHgyQk9CPFKLZOk8yZQEyTjbJwOzESK1eR7QwosbcsLkN1c1WWUZYiCXwORu3UTwJYll4+X2xxJhQ==",
- "requires": {
- "@expo/config-types": "^49.0.0-alpha.1",
- "@expo/json-file": "~8.2.37",
- "@expo/plist": "^0.0.20",
+ "version": "7.8.2",
+ "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.8.2.tgz",
+ "integrity": "sha512-XM2eXA5EvcpmXFCui48+bVy8GTskYSjPf2yC+LliYv8PDcedu7+pdgmbnvH4eZCyHfTMO8/UiF+w8e5WgOEj5A==",
+ "requires": {
+ "@expo/config-types": "^50.0.0-alpha.1",
+ "@expo/fingerprint": "^0.6.0",
+ "@expo/json-file": "~8.3.0",
+ "@expo/plist": "^0.1.0",
"@expo/sdk-runtime-versions": "^1.0.0",
"@react-native/normalize-color": "^2.0.0",
"chalk": "^4.1.2",
@@ -58516,19 +58105,35 @@
"resolve-from": "^5.0.0",
"semver": "^7.5.3",
"slash": "^3.0.0",
+ "slugify": "^1.6.6",
"xcode": "^3.0.1",
"xml2js": "0.6.0"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ }
}
},
"@expo/config-types": {
- "version": "49.0.0",
- "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-49.0.0.tgz",
- "integrity": "sha512-8eyREVi+K2acnMBe/rTIu1dOfyR2+AMnTLHlut+YpMV9OZPdeKV0Bs9BxAewGqBA2slslbQ9N39IS2CuTKpXkA=="
+ "version": "50.0.0",
+ "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-50.0.0.tgz",
+ "integrity": "sha512-0kkhIwXRT6EdFDwn+zTg9R2MZIAEYGn1MVkyRohAd+C9cXOb5RA8WLQi7vuxKF9m1SMtNAUrf0pO+ENK0+/KSw=="
},
"@expo/json-file": {
- "version": "8.2.37",
- "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.2.37.tgz",
- "integrity": "sha512-YaH6rVg11JoTS2P6LsW7ybS2CULjf40AbnAHw2F1eDPuheprNjARZMnyHFPkKv7GuxCy+B9GPcbOKgc4cgA80Q==",
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.3.0.tgz",
+ "integrity": "sha512-yROUeXJXR5goagB8c3muFLCzLmdGOvoPpR5yDNaXrnTp4euNykr9yW0wWhJx4YVRTNOPtGBnEbbJBW+a9q+S6g==",
"requires": {
"@babel/code-frame": "~7.10.4",
"json5": "^2.2.2",
@@ -58536,9 +58141,9 @@
}
},
"@expo/plist": {
- "version": "0.0.20",
- "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.0.20.tgz",
- "integrity": "sha512-UXQ4LXCfTZ580LDHGJ5q62jSTwJFFJ1GqBu8duQMThiHKWbMJ+gajJh6rsB6EJ3aLUr9wcauxneL5LVRFxwBEA==",
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.1.0.tgz",
+ "integrity": "sha512-xWD+8vIFif0wKyuqe3fmnmnSouXYucciZXFzS0ZD5OV9eSAS1RGQI5FaGGJ6zxJ4mpdy/4QzbLdBjnYE5vxA0g==",
"requires": {
"@xmldom/xmldom": "~0.7.7",
"base64-js": "^1.2.3",
@@ -58554,9 +58159,9 @@
}
},
"arg": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz",
- "integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg=="
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
+ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
},
"better-opn": {
"version": "3.0.2",
@@ -58619,6 +58224,19 @@
"universalify": "^0.1.0"
}
},
+ "glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -58691,14 +58309,6 @@
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
},
- "minipass": {
- "version": "3.1.6",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz",
- "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==",
- "requires": {
- "yallist": "^4.0.0"
- }
- },
"onetime": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
@@ -58824,13 +58434,13 @@
}
},
"@expo/config": {
- "version": "8.1.2",
- "resolved": "https://registry.npmjs.org/@expo/config/-/config-8.1.2.tgz",
- "integrity": "sha512-4e7hzPj50mQIlsrzOH6XZ36O094mPfPTIDIH4yv49bWNMc7GFLTofB/lcT+QyxiLaJuC0Wlk9yOLB8DIqmtwug==",
+ "version": "8.5.2",
+ "resolved": "https://registry.npmjs.org/@expo/config/-/config-8.5.2.tgz",
+ "integrity": "sha512-UYy9kWxjQAEDwlX7gwLk0+8IxGPcHJMLnYRYtR5C5xGIV+ML7tCA+qFz1p4gHZRPkJD+k7iZyqBtyqt8xm+zXw==",
"requires": {
"@babel/code-frame": "~7.10.4",
- "@expo/config-plugins": "~7.2.0",
- "@expo/config-types": "^49.0.0-alpha.1",
+ "@expo/config-plugins": "~7.8.2",
+ "@expo/config-types": "^50.0.0",
"@expo/json-file": "^8.2.37",
"getenv": "^1.0.0",
"glob": "7.1.6",
@@ -58850,13 +58460,14 @@
}
},
"@expo/config-plugins": {
- "version": "7.2.5",
- "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.2.5.tgz",
- "integrity": "sha512-w+5ccu1IxBHgyQk9CPFKLZOk8yZQEyTjbJwOzESK1eR7QwosbcsLkN1c1WWUZYiCXwORu3UTwJYll4+X2xxJhQ==",
- "requires": {
- "@expo/config-types": "^49.0.0-alpha.1",
- "@expo/json-file": "~8.2.37",
- "@expo/plist": "^0.0.20",
+ "version": "7.8.2",
+ "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.8.2.tgz",
+ "integrity": "sha512-XM2eXA5EvcpmXFCui48+bVy8GTskYSjPf2yC+LliYv8PDcedu7+pdgmbnvH4eZCyHfTMO8/UiF+w8e5WgOEj5A==",
+ "requires": {
+ "@expo/config-types": "^50.0.0-alpha.1",
+ "@expo/fingerprint": "^0.6.0",
+ "@expo/json-file": "~8.3.0",
+ "@expo/plist": "^0.1.0",
"@expo/sdk-runtime-versions": "^1.0.0",
"@react-native/normalize-color": "^2.0.0",
"chalk": "^4.1.2",
@@ -58867,19 +58478,20 @@
"resolve-from": "^5.0.0",
"semver": "^7.5.3",
"slash": "^3.0.0",
+ "slugify": "^1.6.6",
"xcode": "^3.0.1",
"xml2js": "0.6.0"
}
},
"@expo/config-types": {
- "version": "49.0.0",
- "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-49.0.0.tgz",
- "integrity": "sha512-8eyREVi+K2acnMBe/rTIu1dOfyR2+AMnTLHlut+YpMV9OZPdeKV0Bs9BxAewGqBA2slslbQ9N39IS2CuTKpXkA=="
+ "version": "50.0.0",
+ "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-50.0.0.tgz",
+ "integrity": "sha512-0kkhIwXRT6EdFDwn+zTg9R2MZIAEYGn1MVkyRohAd+C9cXOb5RA8WLQi7vuxKF9m1SMtNAUrf0pO+ENK0+/KSw=="
},
"@expo/json-file": {
- "version": "8.2.37",
- "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.2.37.tgz",
- "integrity": "sha512-YaH6rVg11JoTS2P6LsW7ybS2CULjf40AbnAHw2F1eDPuheprNjARZMnyHFPkKv7GuxCy+B9GPcbOKgc4cgA80Q==",
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.3.0.tgz",
+ "integrity": "sha512-yROUeXJXR5goagB8c3muFLCzLmdGOvoPpR5yDNaXrnTp4euNykr9yW0wWhJx4YVRTNOPtGBnEbbJBW+a9q+S6g==",
"requires": {
"@babel/code-frame": "~7.10.4",
"json5": "^2.2.2",
@@ -58887,9 +58499,9 @@
}
},
"@expo/plist": {
- "version": "0.0.20",
- "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.0.20.tgz",
- "integrity": "sha512-UXQ4LXCfTZ580LDHGJ5q62jSTwJFFJ1GqBu8duQMThiHKWbMJ+gajJh6rsB6EJ3aLUr9wcauxneL5LVRFxwBEA==",
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.1.0.tgz",
+ "integrity": "sha512-xWD+8vIFif0wKyuqe3fmnmnSouXYucciZXFzS0ZD5OV9eSAS1RGQI5FaGGJ6zxJ4mpdy/4QzbLdBjnYE5vxA0g==",
"requires": {
"@xmldom/xmldom": "~0.7.7",
"base64-js": "^1.2.3",
@@ -59037,166 +58649,6 @@
"resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-45.0.0.tgz",
"integrity": "sha512-/QGhhLWyaGautgEyU50UJr5YqKJix5t77ePTwreOVAhmZH+ff3nrrtYTTnccx+qF08ZNQmfAyYMCD3rQfzpiJA=="
},
- "@expo/dev-server": {
- "version": "0.5.5",
- "resolved": "https://registry.npmjs.org/@expo/dev-server/-/dev-server-0.5.5.tgz",
- "integrity": "sha512-t0fT8xH1exwYsH5hh7bAt85VF+gXxg24qrbny2rR/iKoPTWFCd2JNQV8pvfLg51hvrywQ3YCBuT3lU1w7aZxFA==",
- "requires": {
- "@expo/bunyan": "4.0.0",
- "@expo/metro-config": "~0.10.0",
- "@expo/osascript": "2.0.33",
- "@expo/spawn-async": "^1.5.0",
- "body-parser": "^1.20.1",
- "chalk": "^4.0.0",
- "connect": "^3.7.0",
- "fs-extra": "9.0.0",
- "is-docker": "^2.0.0",
- "is-wsl": "^2.1.1",
- "node-fetch": "^2.6.0",
- "open": "^8.3.0",
- "resolve-from": "^5.0.0",
- "serialize-error": "6.0.0",
- "temp-dir": "^2.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "body-parser": {
- "version": "1.20.2",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
- "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
- "requires": {
- "bytes": "3.1.2",
- "content-type": "~1.0.5",
- "debug": "2.6.9",
- "depd": "2.0.0",
- "destroy": "1.2.0",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "on-finished": "2.4.1",
- "qs": "6.11.0",
- "raw-body": "2.5.2",
- "type-is": "~1.6.18",
- "unpipe": "1.0.0"
- }
- },
- "bytes": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
- "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
- },
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "fs-extra": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz",
- "integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==",
- "requires": {
- "at-least-node": "^1.0.0",
- "graceful-fs": "^4.2.0",
- "jsonfile": "^6.0.1",
- "universalify": "^1.0.0"
- }
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
- },
- "iconv-lite": {
- "version": "0.4.24",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
- "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
- "requires": {
- "safer-buffer": ">= 2.1.2 < 3"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
- },
- "qs": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
- "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
- "requires": {
- "side-channel": "^1.0.4"
- }
- },
- "raw-body": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
- "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
- "requires": {
- "bytes": "3.1.2",
- "http-errors": "2.0.0",
- "iconv-lite": "0.4.24",
- "unpipe": "1.0.0"
- }
- },
- "serialize-error": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-6.0.0.tgz",
- "integrity": "sha512-3vmBkMZLQO+BR4RPHcyRGdE09XCF6cvxzk2N2qn8Er3F91cy8Qt7VvEbZBOpaL53qsBbe2cFOefU6tRY6WDelA==",
- "requires": {
- "type-fest": "^0.12.0"
- }
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "requires": {
- "has-flag": "^4.0.0"
- }
- },
- "type-fest": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.12.0.tgz",
- "integrity": "sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg=="
- },
- "universalify": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
- "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug=="
- }
- }
- },
"@expo/devcert": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@expo/devcert/-/devcert-1.1.0.tgz",
@@ -59257,9 +58709,9 @@
}
},
"@expo/env": {
- "version": "0.0.5",
- "resolved": "https://registry.npmjs.org/@expo/env/-/env-0.0.5.tgz",
- "integrity": "sha512-UXuKAqyXfhMQC3gP0OyjXmFX08Z1fkVWiGBN7bYzfoX8LHatjeHrDtI6w5nDvd8XPxPvmqaZoEDw1lW3+dz3oQ==",
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/@expo/env/-/env-0.2.1.tgz",
+ "integrity": "sha512-deZmRS7Dvp18VM8s559dq/ZjPlV1D9vtLoLXwHmCK/JYOvtNptdKsfxcWjI7ewmo6ln2PqgNI9HRI74q6Wk2eA==",
"requires": {
"chalk": "^4.0.0",
"debug": "^4.3.4",
@@ -59323,17 +58775,75 @@
}
}
},
+ "@expo/fingerprint": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.6.0.tgz",
+ "integrity": "sha512-KfpoVRTMwMNJ/Cf5o+Ou8M/Y0EGSTqK+rbi70M2Y0K2qgWNfMJ1gm6sYO9uc8lcTr7YSYM1Rme3dk7QXhpScNA==",
+ "requires": {
+ "@expo/spawn-async": "^1.5.0",
+ "chalk": "^4.1.2",
+ "debug": "^4.3.4",
+ "find-up": "^5.0.0",
+ "minimatch": "^3.0.4",
+ "p-limit": "^3.1.0",
+ "resolve-from": "^5.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
"@expo/image-utils": {
- "version": "0.3.22",
- "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.3.22.tgz",
- "integrity": "sha512-uzq+RERAtkWypOFOLssFnXXqEqKjNj9eXN7e97d/EXUAojNcLDoXc0sL+F5B1I4qtlsnhX01kcpoIBBZD8wZNQ==",
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.4.1.tgz",
+ "integrity": "sha512-EZb+VHSmw+a5s2hS9qksTcWylY0FDaIAVufcxoaRS9tHIXLjW5zcKW7Rhj9dSEbZbRVy9yXXdHKa3GQdUQIOFw==",
"requires": {
"@expo/spawn-async": "1.5.0",
"chalk": "^4.0.0",
"fs-extra": "9.0.0",
"getenv": "^1.0.0",
"jimp-compact": "0.16.1",
- "mime": "^2.4.4",
"node-fetch": "^2.6.0",
"parse-png": "^2.1.0",
"resolve-from": "^5.0.0",
@@ -59469,17 +58979,25 @@
}
},
"@expo/metro-config": {
- "version": "0.10.7",
- "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-0.10.7.tgz",
- "integrity": "sha512-uACymEiyX0447hI4unt+2cemLQkTZXKvTev936NhtsgVnql45EP0V0pzmo/0H0WlHaAGXgvOBZJl8wFqcJ3CbQ==",
+ "version": "0.17.1",
+ "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-0.17.1.tgz",
+ "integrity": "sha512-ZOE0Jx0YTZyPpsGiiE09orGEFgZ5sMrOOFSgOe8zrns925g/uCuEbowyNq38IfQt//3xSl5mW3z0l4rxgi7hHQ==",
"requires": {
- "@expo/config": "~8.1.0",
- "@expo/env": "0.0.5",
- "@expo/json-file": "~8.2.37",
+ "@babel/core": "^7.20.0",
+ "@babel/generator": "^7.20.5",
+ "@babel/parser": "^7.20.0",
+ "@babel/types": "^7.20.0",
+ "@expo/config": "~8.5.0",
+ "@expo/env": "~0.2.0",
+ "@expo/json-file": "~8.3.0",
+ "@expo/spawn-async": "^1.7.2",
+ "babel-preset-fbjs": "^3.4.0",
"chalk": "^4.1.0",
"debug": "^4.3.2",
"find-yarn-workspace-root": "~2.0.0",
+ "fs-extra": "^9.1.0",
"getenv": "^1.0.0",
+ "glob": "^7.2.3",
"jsc-safe-url": "^0.2.4",
"lightningcss": "~1.19.0",
"postcss": "~8.4.21",
@@ -59496,15 +59014,23 @@
}
},
"@expo/json-file": {
- "version": "8.2.37",
- "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.2.37.tgz",
- "integrity": "sha512-YaH6rVg11JoTS2P6LsW7ybS2CULjf40AbnAHw2F1eDPuheprNjARZMnyHFPkKv7GuxCy+B9GPcbOKgc4cgA80Q==",
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.3.0.tgz",
+ "integrity": "sha512-yROUeXJXR5goagB8c3muFLCzLmdGOvoPpR5yDNaXrnTp4euNykr9yW0wWhJx4YVRTNOPtGBnEbbJBW+a9q+S6g==",
"requires": {
"@babel/code-frame": "~7.10.4",
"json5": "^2.2.2",
"write-file-atomic": "^2.3.0"
}
},
+ "@expo/spawn-async": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.7.2.tgz",
+ "integrity": "sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew==",
+ "requires": {
+ "cross-spawn": "^7.0.3"
+ }
+ },
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@@ -59535,6 +59061,19 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
+ "glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -59546,11 +59085,11 @@
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
},
"postcss": {
- "version": "8.4.30",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.30.tgz",
- "integrity": "sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==",
+ "version": "8.4.32",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz",
+ "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==",
"requires": {
- "nanoid": "^3.3.6",
+ "nanoid": "^3.3.7",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
}
@@ -59676,14 +59215,14 @@
}
},
"@expo/prebuild-config": {
- "version": "6.2.6",
- "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-6.2.6.tgz",
- "integrity": "sha512-uFVvDAm9dPg9p1qpnr4CVnpo2hmkZIL5FQz+VlIdXXJpe7ySh/qTGHtKWY/lWUshQkAJ0nwbKGPztGWdABns/Q==",
- "requires": {
- "@expo/config": "~8.1.0",
- "@expo/config-plugins": "~7.2.0",
- "@expo/config-types": "^49.0.0-alpha.1",
- "@expo/image-utils": "0.3.22",
+ "version": "6.7.2",
+ "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-6.7.2.tgz",
+ "integrity": "sha512-Z1GyWfl923wU29YQg6Xik4URls4qcIddWA4vLhW6mUgiRhC3HCf1keHEzK5AtWsrga4bH/H+usAY0OltgABW1w==",
+ "requires": {
+ "@expo/config": "~8.5.0",
+ "@expo/config-plugins": "~7.8.0",
+ "@expo/config-types": "^50.0.0-alpha.1",
+ "@expo/image-utils": "^0.4.0",
"@expo/json-file": "^8.2.37",
"debug": "^4.3.1",
"fs-extra": "^9.0.0",
@@ -59701,13 +59240,14 @@
}
},
"@expo/config-plugins": {
- "version": "7.2.5",
- "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.2.5.tgz",
- "integrity": "sha512-w+5ccu1IxBHgyQk9CPFKLZOk8yZQEyTjbJwOzESK1eR7QwosbcsLkN1c1WWUZYiCXwORu3UTwJYll4+X2xxJhQ==",
- "requires": {
- "@expo/config-types": "^49.0.0-alpha.1",
- "@expo/json-file": "~8.2.37",
- "@expo/plist": "^0.0.20",
+ "version": "7.8.2",
+ "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.8.2.tgz",
+ "integrity": "sha512-XM2eXA5EvcpmXFCui48+bVy8GTskYSjPf2yC+LliYv8PDcedu7+pdgmbnvH4eZCyHfTMO8/UiF+w8e5WgOEj5A==",
+ "requires": {
+ "@expo/config-types": "^50.0.0-alpha.1",
+ "@expo/fingerprint": "^0.6.0",
+ "@expo/json-file": "~8.3.0",
+ "@expo/plist": "^0.1.0",
"@expo/sdk-runtime-versions": "^1.0.0",
"@react-native/normalize-color": "^2.0.0",
"chalk": "^4.1.2",
@@ -59718,19 +59258,20 @@
"resolve-from": "^5.0.0",
"semver": "^7.5.3",
"slash": "^3.0.0",
+ "slugify": "^1.6.6",
"xcode": "^3.0.1",
"xml2js": "0.6.0"
}
},
"@expo/config-types": {
- "version": "49.0.0",
- "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-49.0.0.tgz",
- "integrity": "sha512-8eyREVi+K2acnMBe/rTIu1dOfyR2+AMnTLHlut+YpMV9OZPdeKV0Bs9BxAewGqBA2slslbQ9N39IS2CuTKpXkA=="
+ "version": "50.0.0",
+ "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-50.0.0.tgz",
+ "integrity": "sha512-0kkhIwXRT6EdFDwn+zTg9R2MZIAEYGn1MVkyRohAd+C9cXOb5RA8WLQi7vuxKF9m1SMtNAUrf0pO+ENK0+/KSw=="
},
"@expo/json-file": {
- "version": "8.2.37",
- "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.2.37.tgz",
- "integrity": "sha512-YaH6rVg11JoTS2P6LsW7ybS2CULjf40AbnAHw2F1eDPuheprNjARZMnyHFPkKv7GuxCy+B9GPcbOKgc4cgA80Q==",
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.3.0.tgz",
+ "integrity": "sha512-yROUeXJXR5goagB8c3muFLCzLmdGOvoPpR5yDNaXrnTp4euNykr9yW0wWhJx4YVRTNOPtGBnEbbJBW+a9q+S6g==",
"requires": {
"@babel/code-frame": "~7.10.4",
"json5": "^2.2.2",
@@ -59738,9 +59279,9 @@
}
},
"@expo/plist": {
- "version": "0.0.20",
- "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.0.20.tgz",
- "integrity": "sha512-UXQ4LXCfTZ580LDHGJ5q62jSTwJFFJ1GqBu8duQMThiHKWbMJ+gajJh6rsB6EJ3aLUr9wcauxneL5LVRFxwBEA==",
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.1.0.tgz",
+ "integrity": "sha512-xWD+8vIFif0wKyuqe3fmnmnSouXYucciZXFzS0ZD5OV9eSAS1RGQI5FaGGJ6zxJ4mpdy/4QzbLdBjnYE5vxA0g==",
"requires": {
"@xmldom/xmldom": "~0.7.7",
"base64-js": "^1.2.3",
@@ -59842,6 +59383,17 @@
"resolved": "https://registry.npmjs.org/@expo/sdk-runtime-versions/-/sdk-runtime-versions-1.0.0.tgz",
"integrity": "sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ=="
},
+ "@expo/server": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@expo/server/-/server-0.3.0.tgz",
+ "integrity": "sha512-5oIqedpLVMnf1LGI9Xd5OOGmK3DjgH9VpuqVN4e/6DwLT05RZJMyI7ylfG6QSy1e44yOgjv242tLyg0e/zdZ+A==",
+ "requires": {
+ "@remix-run/node": "^1.19.3",
+ "abort-controller": "^3.0.0",
+ "debug": "^4.3.4",
+ "source-map-support": "~0.5.21"
+ }
+ },
"@expo/spawn-async": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.5.0.tgz",
@@ -59901,9 +59453,9 @@
"integrity": "sha512-TI+l71+5aSKnShYclFa14Kum+hQMZ86b95SH6tQUG3qZEmLTarvWpKwqtTwQKqvlJSJrpFiSFu3eCuZokY6zWA=="
},
"@expo/xcpretty": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@expo/xcpretty/-/xcpretty-4.2.2.tgz",
- "integrity": "sha512-Lke/geldJqUV0Dfxg5/QIOugOzdqZ/rQ9yHKSgGbjZtG1uiSqWyFwWvXmrdd3/sIdX33eykGvIcf+OrvvcXVUw==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@expo/xcpretty/-/xcpretty-4.3.0.tgz",
+ "integrity": "sha512-whBbvHZ2Q10T5TNmN0z5NbO6C9ZDw+XUTu8h6vVMnMzQrbGexc9oaCCZfz+L3Q7TEL5vfr+9L86nY62c3Bsm+g==",
"requires": {
"@babel/code-frame": "7.10.4",
"chalk": "^4.1.0",
@@ -60159,7 +59711,6 @@
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
- "dev": true,
"requires": {
"string-width": "^5.1.2",
"string-width-cjs": "npm:string-width@^4.2.0",
@@ -60172,26 +59723,22 @@
"ansi-regex": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
- "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
- "dev": true
+ "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA=="
},
"ansi-styles": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
- "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
- "dev": true
+ "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="
},
"emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
- "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
- "dev": true
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
},
"string-width": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
- "dev": true,
"requires": {
"eastasianwidth": "^0.2.0",
"emoji-regex": "^9.2.2",
@@ -60202,7 +59749,6 @@
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
- "dev": true,
"requires": {
"ansi-regex": "^6.0.1"
}
@@ -60211,7 +59757,6 @@
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
- "dev": true,
"requires": {
"ansi-styles": "^6.1.0",
"string-width": "^5.0.1",
@@ -60220,6 +59765,11 @@
}
}
},
+ "@isaacs/ttlcache": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz",
+ "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA=="
+ },
"@istanbuljs/load-nyc-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@@ -60459,19 +60009,19 @@
}
},
"@jest/create-cache-key-function": {
- "version": "29.5.0",
- "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.5.0.tgz",
- "integrity": "sha512-LIDZyZgnZss7uikvBKBB/USWwG+GO8+GnwRWT+YkCGDGsqLQlhm9BC3z6+7+eMs1kUlvXQIWEzBR8Q2Pnvx6lg==",
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz",
+ "integrity": "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==",
"requires": {
- "@jest/types": "^29.5.0"
+ "@jest/types": "^29.6.3"
},
"dependencies": {
"@jest/types": {
- "version": "29.5.0",
- "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz",
- "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz",
+ "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
"requires": {
- "@jest/schemas": "^29.4.3",
+ "@jest/schemas": "^29.6.3",
"@types/istanbul-lib-coverage": "^2.0.0",
"@types/istanbul-reports": "^3.0.0",
"@types/node": "*",
@@ -60480,9 +60030,9 @@
}
},
"@types/yargs": {
- "version": "17.0.24",
- "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz",
- "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==",
+ "version": "17.0.31",
+ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.31.tgz",
+ "integrity": "sha512-bocYSx4DI8TmdlvxqGpVNXOgCNR1Jj0gNPhhAY+iz1rgKDAaYrAYdFYnhDV1IFuiuVc9HkOwyDcFxaTElF3/wg==",
"requires": {
"@types/yargs-parser": "*"
}
@@ -60533,14 +60083,14 @@
}
},
"@jest/environment": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.6.2.tgz",
- "integrity": "sha512-AEcW43C7huGd/vogTddNNTDRpO6vQ2zaQNrttvWV18ArBx9Z56h7BIsXkNFJVOO4/kblWEQz30ckw0+L3izc+Q==",
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz",
+ "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==",
"requires": {
- "@jest/fake-timers": "^29.6.2",
- "@jest/types": "^29.6.1",
+ "@jest/fake-timers": "^29.7.0",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
- "jest-mock": "^29.6.2"
+ "jest-mock": "^29.7.0"
},
"dependencies": {
"@jest/types": {
@@ -60627,16 +60177,16 @@
}
},
"@jest/fake-timers": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.6.2.tgz",
- "integrity": "sha512-euZDmIlWjm1Z0lJ1D0f7a0/y5Kh/koLFMUBE5SUYWrmy8oNhJpbTBDAP6CxKnadcMLDoDf4waRYCe35cH6G6PA==",
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz",
+ "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==",
"requires": {
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"@sinonjs/fake-timers": "^10.0.2",
"@types/node": "*",
- "jest-message-util": "^29.6.2",
- "jest-mock": "^29.6.2",
- "jest-util": "^29.6.2"
+ "jest-message-util": "^29.7.0",
+ "jest-mock": "^29.7.0",
+ "jest-util": "^29.7.0"
},
"dependencies": {
"@jest/types": {
@@ -61966,7 +61516,6 @@
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
- "dev": true,
"optional": true
},
"@pmmmwh/react-refresh-webpack-plugin": {
@@ -62279,9 +61828,9 @@
}
},
"@react-native-async-storage/async-storage": {
- "version": "1.19.3",
- "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.19.3.tgz",
- "integrity": "sha512-CwGfoHCWdPOTPS+2fW6YRE1fFBpT9++ahLEroX5hkgwyoQ+TkmjOaUxixdEIoVua9Pz5EF2pGOIJzqOTMWfBlA==",
+ "version": "1.21.0",
+ "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.21.0.tgz",
+ "integrity": "sha512-JL0w36KuFHFCvnbOXRekqVAUplmOyT/OuCQkogo6X98MtpSaJOKEAeZnYO8JB0U/RIEixZaGI5px73YbRm/oag==",
"requires": {
"merge-options": "^3.0.4"
}
@@ -62299,26 +61848,27 @@
"requires": {}
},
"@react-native-community/cli": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-11.3.6.tgz",
- "integrity": "sha512-bdwOIYTBVQ9VK34dsf6t3u6vOUU5lfdhKaAxiAVArjsr7Je88Bgs4sAbsOYsNK3tkE8G77U6wLpekknXcanlww==",
- "requires": {
- "@react-native-community/cli-clean": "11.3.6",
- "@react-native-community/cli-config": "11.3.6",
- "@react-native-community/cli-debugger-ui": "11.3.6",
- "@react-native-community/cli-doctor": "11.3.6",
- "@react-native-community/cli-hermes": "11.3.6",
- "@react-native-community/cli-plugin-metro": "11.3.6",
- "@react-native-community/cli-server-api": "11.3.6",
- "@react-native-community/cli-tools": "11.3.6",
- "@react-native-community/cli-types": "11.3.6",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-12.3.0.tgz",
+ "integrity": "sha512-XeQohi2E+S2+MMSz97QcEZ/bWpi8sfKiQg35XuYeJkc32Til2g0b97jRpn0/+fV0BInHoG1CQYWwHA7opMsrHg==",
+ "requires": {
+ "@react-native-community/cli-clean": "12.3.0",
+ "@react-native-community/cli-config": "12.3.0",
+ "@react-native-community/cli-debugger-ui": "12.3.0",
+ "@react-native-community/cli-doctor": "12.3.0",
+ "@react-native-community/cli-hermes": "12.3.0",
+ "@react-native-community/cli-plugin-metro": "12.3.0",
+ "@react-native-community/cli-server-api": "12.3.0",
+ "@react-native-community/cli-tools": "12.3.0",
+ "@react-native-community/cli-types": "12.3.0",
"chalk": "^4.1.2",
"commander": "^9.4.1",
+ "deepmerge": "^4.3.0",
"execa": "^5.0.0",
"find-up": "^4.1.0",
"fs-extra": "^8.1.0",
"graceful-fs": "^4.1.3",
- "prompts": "^2.4.0",
+ "prompts": "^2.4.2",
"semver": "^7.5.2"
},
"dependencies": {
@@ -62434,14 +61984,13 @@
}
},
"@react-native-community/cli-clean": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-11.3.6.tgz",
- "integrity": "sha512-jOOaeG5ebSXTHweq1NznVJVAFKtTFWL4lWgUXl845bCGX7t1lL8xQNWHKwT8Oh1pGR2CI3cKmRjY4hBg+pEI9g==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-12.3.0.tgz",
+ "integrity": "sha512-iAgLCOWYRGh9ukr+eVQnhkV/OqN3V2EGd/in33Ggn/Mj4uO6+oUncXFwB+yjlyaUNz6FfjudhIz09yYGSF+9sg==",
"requires": {
- "@react-native-community/cli-tools": "11.3.6",
+ "@react-native-community/cli-tools": "12.3.0",
"chalk": "^4.1.2",
- "execa": "^5.0.0",
- "prompts": "^2.4.0"
+ "execa": "^5.0.0"
},
"dependencies": {
"ansi-styles": {
@@ -62490,11 +62039,11 @@
}
},
"@react-native-community/cli-config": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-11.3.6.tgz",
- "integrity": "sha512-edy7fwllSFLan/6BG6/rznOBCLPrjmJAE10FzkEqNLHowi0bckiAPg1+1jlgQ2qqAxV5kuk+c9eajVfQvPLYDA==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-12.3.0.tgz",
+ "integrity": "sha512-BrTn5ndFD9uOxO8kxBQ32EpbtOvAsQExGPI7SokdI4Zlve70FziLtTq91LTlTUgMq1InVZn/jJb3VIDk6BTInQ==",
"requires": {
- "@react-native-community/cli-tools": "11.3.6",
+ "@react-native-community/cli-tools": "12.3.0",
"chalk": "^4.1.2",
"cosmiconfig": "^5.1.0",
"deepmerge": "^4.3.0",
@@ -62582,34 +62131,33 @@
}
},
"@react-native-community/cli-debugger-ui": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-11.3.6.tgz",
- "integrity": "sha512-jhMOSN/iOlid9jn/A2/uf7HbC3u7+lGktpeGSLnHNw21iahFBzcpuO71ekEdlmTZ4zC/WyxBXw9j2ka33T358w==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-12.3.0.tgz",
+ "integrity": "sha512-w3b0iwjQlk47GhZWHaeTG8kKH09NCMUJO729xSdMBXE8rlbm4kHpKbxQY9qKb6NlfWSJN4noGY+FkNZS2rRwnQ==",
"requires": {
"serve-static": "^1.13.1"
}
},
"@react-native-community/cli-doctor": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-11.3.6.tgz",
- "integrity": "sha512-UT/Tt6omVPi1j6JEX+CObc85eVFghSZwy4GR9JFMsO7gNg2Tvcu1RGWlUkrbmWMAMHw127LUu6TGK66Ugu1NLA==",
- "requires": {
- "@react-native-community/cli-config": "11.3.6",
- "@react-native-community/cli-platform-android": "11.3.6",
- "@react-native-community/cli-platform-ios": "11.3.6",
- "@react-native-community/cli-tools": "11.3.6",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-12.3.0.tgz",
+ "integrity": "sha512-BPCwNNesoQMkKsxB08Ayy6URgGQ8Kndv6mMhIvJSNdST3J1+x3ehBHXzG9B9Vfi+DrTKRb8lmEl/b/7VkDlPkA==",
+ "requires": {
+ "@react-native-community/cli-config": "12.3.0",
+ "@react-native-community/cli-platform-android": "12.3.0",
+ "@react-native-community/cli-platform-ios": "12.3.0",
+ "@react-native-community/cli-tools": "12.3.0",
"chalk": "^4.1.2",
"command-exists": "^1.2.8",
- "envinfo": "^7.7.2",
+ "deepmerge": "^4.3.0",
+ "envinfo": "^7.10.0",
"execa": "^5.0.0",
"hermes-profile-transformer": "^0.0.6",
"ip": "^1.1.5",
"node-stream-zip": "^1.9.1",
"ora": "^5.4.1",
- "prompts": "^2.4.0",
"semver": "^7.5.2",
"strip-ansi": "^5.2.0",
- "sudo-prompt": "^9.0.0",
"wcwidth": "^1.0.1",
"yaml": "^2.2.1"
},
@@ -62673,12 +62221,12 @@
}
},
"@react-native-community/cli-hermes": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-11.3.6.tgz",
- "integrity": "sha512-O55YAYGZ3XynpUdePPVvNuUPGPY0IJdctLAOHme73OvS80gNwfntHDXfmY70TGHWIfkK2zBhA0B+2v8s5aTyTA==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-12.3.0.tgz",
+ "integrity": "sha512-G6FxpeZBO4AimKZwtWR3dpXRqTvsmEqlIkkxgwthdzn3LbVjDVIXKpVYU9PkR5cnT+KuAUxO0WwthrJ6Nmrrlg==",
"requires": {
- "@react-native-community/cli-platform-android": "11.3.6",
- "@react-native-community/cli-tools": "11.3.6",
+ "@react-native-community/cli-platform-android": "12.3.0",
+ "@react-native-community/cli-tools": "12.3.0",
"chalk": "^4.1.2",
"hermes-profile-transformer": "^0.0.6",
"ip": "^1.1.5"
@@ -62735,13 +62283,14 @@
}
},
"@react-native-community/cli-platform-android": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-11.3.6.tgz",
- "integrity": "sha512-ZARrpLv5tn3rmhZc//IuDM1LSAdYnjUmjrp58RynlvjLDI4ZEjBAGCQmgysRgXAsK7ekMrfkZgemUczfn9td2A==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-12.3.0.tgz",
+ "integrity": "sha512-VU1NZw63+GLU2TnyQ919bEMThpHQ/oMFju9MCfrd3pyPJz4Sn+vc3NfnTDUVA5Z5yfLijFOkHIHr4vo/C9bjnw==",
"requires": {
- "@react-native-community/cli-tools": "11.3.6",
+ "@react-native-community/cli-tools": "12.3.0",
"chalk": "^4.1.2",
"execa": "^5.0.0",
+ "fast-xml-parser": "^4.2.4",
"glob": "^7.1.3",
"logkitty": "^0.7.1"
},
@@ -62792,11 +62341,11 @@
}
},
"@react-native-community/cli-platform-ios": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-11.3.6.tgz",
- "integrity": "sha512-tZ9VbXWiRW+F+fbZzpLMZlj93g3Q96HpuMsS6DRhrTiG+vMQ3o6oPWSEEmMGOvJSYU7+y68Dc9ms2liC7VD6cw==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-12.3.0.tgz",
+ "integrity": "sha512-H95Sgt3wT7L8V75V0syFJDtv4YgqK5zbu69ko4yrXGv8dv2EBi6qZP0VMmkqXDamoPm9/U7tDTdbcf26ctnLfg==",
"requires": {
- "@react-native-community/cli-tools": "11.3.6",
+ "@react-native-community/cli-tools": "12.3.0",
"chalk": "^4.1.2",
"execa": "^5.0.0",
"fast-xml-parser": "^4.0.12",
@@ -62850,533 +62399,17 @@
}
},
"@react-native-community/cli-plugin-metro": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-11.3.6.tgz",
- "integrity": "sha512-D97racrPX3069ibyabJNKw9aJpVcaZrkYiEzsEnx50uauQtPDoQ1ELb/5c6CtMhAEGKoZ0B5MS23BbsSZcLs2g==",
- "requires": {
- "@react-native-community/cli-server-api": "11.3.6",
- "@react-native-community/cli-tools": "11.3.6",
- "chalk": "^4.1.2",
- "execa": "^5.0.0",
- "metro": "0.76.7",
- "metro-config": "0.76.7",
- "metro-core": "0.76.7",
- "metro-react-native-babel-transformer": "0.76.7",
- "metro-resolver": "0.76.7",
- "metro-runtime": "0.76.7",
- "readline": "^1.3.0"
- },
- "dependencies": {
- "@jest/types": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz",
- "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==",
- "requires": {
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^16.0.0",
- "chalk": "^4.0.0"
- }
- },
- "@types/yargs": {
- "version": "16.0.6",
- "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.6.tgz",
- "integrity": "sha512-oTP7/Q13GSPrgcwEwdlnkoZSQ1Hg9THe644qq8PG6hhJzjZ3qj1JjEFPIwWV/IXVs5XGIVqtkNOS9kh63WIJ+A==",
- "requires": {
- "@types/yargs-parser": "*"
- }
- },
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "ci-info": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
- "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="
- },
- "cliui": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
- "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
- "requires": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.1",
- "wrap-ansi": "^7.0.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
- },
- "cosmiconfig": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
- "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
- "requires": {
- "import-fresh": "^2.0.0",
- "is-directory": "^0.3.1",
- "js-yaml": "^3.13.1",
- "parse-json": "^4.0.0"
- }
- },
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
- },
- "import-fresh": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
- "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==",
- "requires": {
- "caller-path": "^2.0.0",
- "resolve-from": "^3.0.0"
- }
- },
- "jest-regex-util": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz",
- "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg=="
- },
- "jest-util": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz",
- "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==",
- "requires": {
- "@jest/types": "^27.5.1",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "ci-info": "^3.2.0",
- "graceful-fs": "^4.2.9",
- "picomatch": "^2.2.3"
- },
- "dependencies": {
- "ci-info": {
- "version": "3.8.0",
- "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz",
- "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw=="
- }
- }
- },
- "jest-worker": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
- "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
- "requires": {
- "@types/node": "*",
- "merge-stream": "^2.0.0",
- "supports-color": "^8.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "8.1.1",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
- "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "metro": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro/-/metro-0.76.7.tgz",
- "integrity": "sha512-67ZGwDeumEPnrHI+pEDSKH2cx+C81Gx8Mn5qOtmGUPm/Up9Y4I1H2dJZ5n17MWzejNo0XAvPh0QL0CrlJEODVQ==",
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "@babel/core": "^7.20.0",
- "@babel/generator": "^7.20.0",
- "@babel/parser": "^7.20.0",
- "@babel/template": "^7.0.0",
- "@babel/traverse": "^7.20.0",
- "@babel/types": "^7.20.0",
- "accepts": "^1.3.7",
- "async": "^3.2.2",
- "chalk": "^4.0.0",
- "ci-info": "^2.0.0",
- "connect": "^3.6.5",
- "debug": "^2.2.0",
- "denodeify": "^1.2.1",
- "error-stack-parser": "^2.0.6",
- "graceful-fs": "^4.2.4",
- "hermes-parser": "0.12.0",
- "image-size": "^1.0.2",
- "invariant": "^2.2.4",
- "jest-worker": "^27.2.0",
- "jsc-safe-url": "^0.2.2",
- "lodash.throttle": "^4.1.1",
- "metro-babel-transformer": "0.76.7",
- "metro-cache": "0.76.7",
- "metro-cache-key": "0.76.7",
- "metro-config": "0.76.7",
- "metro-core": "0.76.7",
- "metro-file-map": "0.76.7",
- "metro-inspector-proxy": "0.76.7",
- "metro-minify-terser": "0.76.7",
- "metro-minify-uglify": "0.76.7",
- "metro-react-native-babel-preset": "0.76.7",
- "metro-resolver": "0.76.7",
- "metro-runtime": "0.76.7",
- "metro-source-map": "0.76.7",
- "metro-symbolicate": "0.76.7",
- "metro-transform-plugins": "0.76.7",
- "metro-transform-worker": "0.76.7",
- "mime-types": "^2.1.27",
- "node-fetch": "^2.2.0",
- "nullthrows": "^1.1.1",
- "rimraf": "^3.0.2",
- "serialize-error": "^2.1.0",
- "source-map": "^0.5.6",
- "strip-ansi": "^6.0.0",
- "throat": "^5.0.0",
- "ws": "^7.5.1",
- "yargs": "^17.6.2"
- }
- },
- "metro-babel-transformer": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.76.7.tgz",
- "integrity": "sha512-bgr2OFn0J4r0qoZcHrwEvccF7g9k3wdgTOgk6gmGHrtlZ1Jn3oCpklW/DfZ9PzHfjY2mQammKTc19g/EFGyOJw==",
- "requires": {
- "@babel/core": "^7.20.0",
- "hermes-parser": "0.12.0",
- "nullthrows": "^1.1.1"
- }
- },
- "metro-cache": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.76.7.tgz",
- "integrity": "sha512-nWBMztrs5RuSxZRI7hgFgob5PhYDmxICh9FF8anm9/ito0u0vpPvRxt7sRu8fyeD2AHdXqE7kX32rWY0LiXgeg==",
- "requires": {
- "metro-core": "0.76.7",
- "rimraf": "^3.0.2"
- }
- },
- "metro-cache-key": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.76.7.tgz",
- "integrity": "sha512-0pecoIzwsD/Whn/Qfa+SDMX2YyasV0ndbcgUFx7w1Ct2sLHClujdhQ4ik6mvQmsaOcnGkIyN0zcceMDjC2+BFQ=="
- },
- "metro-config": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.76.7.tgz",
- "integrity": "sha512-CFDyNb9bqxZemiChC/gNdXZ7OQkIwmXzkrEXivcXGbgzlt/b2juCv555GWJHyZSlorwnwJfY3uzAFu4A9iRVfg==",
- "requires": {
- "connect": "^3.6.5",
- "cosmiconfig": "^5.0.5",
- "jest-validate": "^29.2.1",
- "metro": "0.76.7",
- "metro-cache": "0.76.7",
- "metro-core": "0.76.7",
- "metro-runtime": "0.76.7"
- }
- },
- "metro-core": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.76.7.tgz",
- "integrity": "sha512-0b8KfrwPmwCMW+1V7ZQPkTy2tsEKZjYG9Pu1PTsu463Z9fxX7WaR0fcHFshv+J1CnQSUTwIGGjbNvj1teKe+pw==",
- "requires": {
- "lodash.throttle": "^4.1.1",
- "metro-resolver": "0.76.7"
- }
- },
- "metro-file-map": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.76.7.tgz",
- "integrity": "sha512-s+zEkTcJ4mOJTgEE2ht4jIo1DZfeWreQR3tpT3gDV/Y/0UQ8aJBTv62dE775z0GLsWZApiblAYZsj7ZE8P06nw==",
- "requires": {
- "anymatch": "^3.0.3",
- "debug": "^2.2.0",
- "fb-watchman": "^2.0.0",
- "fsevents": "^2.3.2",
- "graceful-fs": "^4.2.4",
- "invariant": "^2.2.4",
- "jest-regex-util": "^27.0.6",
- "jest-util": "^27.2.0",
- "jest-worker": "^27.2.0",
- "micromatch": "^4.0.4",
- "node-abort-controller": "^3.1.1",
- "nullthrows": "^1.1.1",
- "walker": "^1.0.7"
- }
- },
- "metro-inspector-proxy": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.76.7.tgz",
- "integrity": "sha512-rNZ/6edTl/1qUekAhAbaFjczMphM50/UjtxiKulo6vqvgn/Mjd9hVqDvVYfAMZXqPvlusD88n38UjVYPkruLSg==",
- "requires": {
- "connect": "^3.6.5",
- "debug": "^2.2.0",
- "node-fetch": "^2.2.0",
- "ws": "^7.5.1",
- "yargs": "^17.6.2"
- }
- },
- "metro-minify-terser": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.76.7.tgz",
- "integrity": "sha512-FQiZGhIxCzhDwK4LxyPMLlq0Tsmla10X7BfNGlYFK0A5IsaVKNJbETyTzhpIwc+YFRT4GkFFwgo0V2N5vxO5HA==",
- "requires": {
- "terser": "^5.15.0"
- }
- },
- "metro-minify-uglify": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.76.7.tgz",
- "integrity": "sha512-FuXIU3j2uNcSvQtPrAJjYWHruPiQ+EpE++J9Z+VznQKEHcIxMMoQZAfIF2IpZSrZYfLOjVFyGMvj41jQMxV1Vw==",
- "requires": {
- "uglify-es": "^3.1.9"
- }
- },
- "metro-react-native-babel-preset": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.76.7.tgz",
- "integrity": "sha512-R25wq+VOSorAK3hc07NW0SmN8z9S/IR0Us0oGAsBcMZnsgkbOxu77Mduqf+f4is/wnWHc5+9bfiqdLnaMngiVw==",
- "requires": {
- "@babel/core": "^7.20.0",
- "@babel/plugin-proposal-async-generator-functions": "^7.0.0",
- "@babel/plugin-proposal-class-properties": "^7.18.0",
- "@babel/plugin-proposal-export-default-from": "^7.0.0",
- "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.0",
- "@babel/plugin-proposal-numeric-separator": "^7.0.0",
- "@babel/plugin-proposal-object-rest-spread": "^7.20.0",
- "@babel/plugin-proposal-optional-catch-binding": "^7.0.0",
- "@babel/plugin-proposal-optional-chaining": "^7.20.0",
- "@babel/plugin-syntax-dynamic-import": "^7.8.0",
- "@babel/plugin-syntax-export-default-from": "^7.0.0",
- "@babel/plugin-syntax-flow": "^7.18.0",
- "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0",
- "@babel/plugin-syntax-optional-chaining": "^7.0.0",
- "@babel/plugin-transform-arrow-functions": "^7.0.0",
- "@babel/plugin-transform-async-to-generator": "^7.20.0",
- "@babel/plugin-transform-block-scoping": "^7.0.0",
- "@babel/plugin-transform-classes": "^7.0.0",
- "@babel/plugin-transform-computed-properties": "^7.0.0",
- "@babel/plugin-transform-destructuring": "^7.20.0",
- "@babel/plugin-transform-flow-strip-types": "^7.20.0",
- "@babel/plugin-transform-function-name": "^7.0.0",
- "@babel/plugin-transform-literals": "^7.0.0",
- "@babel/plugin-transform-modules-commonjs": "^7.0.0",
- "@babel/plugin-transform-named-capturing-groups-regex": "^7.0.0",
- "@babel/plugin-transform-parameters": "^7.0.0",
- "@babel/plugin-transform-react-display-name": "^7.0.0",
- "@babel/plugin-transform-react-jsx": "^7.0.0",
- "@babel/plugin-transform-react-jsx-self": "^7.0.0",
- "@babel/plugin-transform-react-jsx-source": "^7.0.0",
- "@babel/plugin-transform-runtime": "^7.0.0",
- "@babel/plugin-transform-shorthand-properties": "^7.0.0",
- "@babel/plugin-transform-spread": "^7.0.0",
- "@babel/plugin-transform-sticky-regex": "^7.0.0",
- "@babel/plugin-transform-typescript": "^7.5.0",
- "@babel/plugin-transform-unicode-regex": "^7.0.0",
- "@babel/template": "^7.0.0",
- "babel-plugin-transform-flow-enums": "^0.0.2",
- "react-refresh": "^0.4.0"
- }
- },
- "metro-react-native-babel-transformer": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.76.7.tgz",
- "integrity": "sha512-W6lW3J7y/05ph3c2p3KKJNhH0IdyxdOCbQ5it7aM2MAl0SM4wgKjaV6EYv9b3rHklpV6K3qMH37UKVcjMooWiA==",
- "requires": {
- "@babel/core": "^7.20.0",
- "babel-preset-fbjs": "^3.4.0",
- "hermes-parser": "0.12.0",
- "metro-react-native-babel-preset": "0.76.7",
- "nullthrows": "^1.1.1"
- }
- },
- "metro-resolver": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.76.7.tgz",
- "integrity": "sha512-pC0Wgq29HHIHrwz23xxiNgylhI8Rq1V01kQaJ9Kz11zWrIdlrH0ZdnJ7GC6qA0ErROG+cXmJ0rJb8/SW1Zp2IA=="
- },
- "metro-runtime": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.76.7.tgz",
- "integrity": "sha512-MuWHubQHymUWBpZLwuKZQgA/qbb35WnDAKPo83rk7JRLIFPvzXSvFaC18voPuzJBt1V98lKQIonh6MiC9gd8Ug==",
- "requires": {
- "@babel/runtime": "^7.0.0",
- "react-refresh": "^0.4.0"
- }
- },
- "metro-source-map": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.76.7.tgz",
- "integrity": "sha512-Prhx7PeRV1LuogT0Kn5VjCuFu9fVD68eefntdWabrksmNY6mXK8pRqzvNJOhTojh6nek+RxBzZeD6MIOOyXS6w==",
- "requires": {
- "@babel/traverse": "^7.20.0",
- "@babel/types": "^7.20.0",
- "invariant": "^2.2.4",
- "metro-symbolicate": "0.76.7",
- "nullthrows": "^1.1.1",
- "ob1": "0.76.7",
- "source-map": "^0.5.6",
- "vlq": "^1.0.0"
- }
- },
- "metro-symbolicate": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.76.7.tgz",
- "integrity": "sha512-p0zWEME5qLSL1bJb93iq+zt5fz3sfVn9xFYzca1TJIpY5MommEaS64Va87lp56O0sfEIvh4307Oaf/ZzRjuLiQ==",
- "requires": {
- "invariant": "^2.2.4",
- "metro-source-map": "0.76.7",
- "nullthrows": "^1.1.1",
- "source-map": "^0.5.6",
- "through2": "^2.0.1",
- "vlq": "^1.0.0"
- }
- },
- "metro-transform-plugins": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.76.7.tgz",
- "integrity": "sha512-iSmnjVApbdivjuzb88Orb0JHvcEt5veVyFAzxiS5h0QB+zV79w6JCSqZlHCrbNOkOKBED//LqtKbFVakxllnNg==",
- "requires": {
- "@babel/core": "^7.20.0",
- "@babel/generator": "^7.20.0",
- "@babel/template": "^7.0.0",
- "@babel/traverse": "^7.20.0",
- "nullthrows": "^1.1.1"
- }
- },
- "metro-transform-worker": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.76.7.tgz",
- "integrity": "sha512-cGvELqFMVk9XTC15CMVzrCzcO6sO1lURfcbgjuuPdzaWuD11eEyocvkTX0DPiRjsvgAmicz4XYxVzgYl3MykDw==",
- "requires": {
- "@babel/core": "^7.20.0",
- "@babel/generator": "^7.20.0",
- "@babel/parser": "^7.20.0",
- "@babel/types": "^7.20.0",
- "babel-preset-fbjs": "^3.4.0",
- "metro": "0.76.7",
- "metro-babel-transformer": "0.76.7",
- "metro-cache": "0.76.7",
- "metro-cache-key": "0.76.7",
- "metro-source-map": "0.76.7",
- "metro-transform-plugins": "0.76.7",
- "nullthrows": "^1.1.1"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
- },
- "ob1": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.76.7.tgz",
- "integrity": "sha512-BQdRtxxoUNfSoZxqeBGOyuT9nEYSn18xZHwGMb0mMVpn2NBcYbnyKY4BK2LIHRgw33CBGlUmE+KMaNvyTpLLtQ=="
- },
- "parse-json": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
- "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
- "requires": {
- "error-ex": "^1.3.1",
- "json-parse-better-errors": "^1.0.1"
- }
- },
- "react-refresh": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz",
- "integrity": "sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA=="
- },
- "resolve-from": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
- "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw=="
- },
- "serialize-error": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz",
- "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw=="
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "requires": {
- "has-flag": "^4.0.0"
- }
- },
- "ws": {
- "version": "7.5.9",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
- "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
- "requires": {}
- },
- "y18n": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
- },
- "yargs": {
- "version": "17.7.2",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
- "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
- "requires": {
- "cliui": "^8.0.1",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "require-directory": "^2.1.1",
- "string-width": "^4.2.3",
- "y18n": "^5.0.5",
- "yargs-parser": "^21.1.1"
- }
- },
- "yargs-parser": {
- "version": "21.1.1",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
- "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="
- }
- }
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-12.3.0.tgz",
+ "integrity": "sha512-tYNHIYnNmxrBcsqbE2dAnLMzlKI3Cp1p1xUgTrNaOMsGPDN1epzNfa34n6Nps3iwKElSL7Js91CzYNqgTalucA=="
},
"@react-native-community/cli-server-api": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-11.3.6.tgz",
- "integrity": "sha512-8GUKodPnURGtJ9JKg8yOHIRtWepPciI3ssXVw5jik7+dZ43yN8P5BqCoDaq8e1H1yRer27iiOfT7XVnwk8Dueg==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-12.3.0.tgz",
+ "integrity": "sha512-Rode8NrdyByC+lBKHHn+/W8Zu0c+DajJvLmOWbe2WY/ECvnwcd9MHHbu92hlT2EQaJ9LbLhGrSbQE3cQy9EOCw==",
"requires": {
- "@react-native-community/cli-debugger-ui": "11.3.6",
- "@react-native-community/cli-tools": "11.3.6",
+ "@react-native-community/cli-debugger-ui": "12.3.0",
+ "@react-native-community/cli-tools": "12.3.0",
"compression": "^1.7.1",
"connect": "^3.6.5",
"errorhandler": "^1.5.1",
@@ -63437,9 +62470,9 @@
}
},
"@react-native-community/cli-tools": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-11.3.6.tgz",
- "integrity": "sha512-JpmUTcDwAGiTzLsfMlIAYpCMSJ9w2Qlf7PU7mZIRyEu61UzEawyw83DkqfbzDPBuRwRnaeN44JX2CP/yTO3ThQ==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-12.3.0.tgz",
+ "integrity": "sha512-2GafnCr8D88VdClwnm9KZfkEb+lzVoFdr/7ybqhdeYM0Vnt/tr2N+fM1EQzwI1DpzXiBzTYemw8GjRq+Utcz2Q==",
"requires": {
"appdirsjs": "^1.2.4",
"chalk": "^4.1.2",
@@ -63449,7 +62482,8 @@
"open": "^6.2.0",
"ora": "^5.4.1",
"semver": "^7.5.2",
- "shell-quote": "^1.7.3"
+ "shell-quote": "^1.7.3",
+ "sudo-prompt": "^9.0.0"
},
"dependencies": {
"ansi-styles": {
@@ -63511,9 +62545,9 @@
}
},
"@react-native-community/cli-types": {
- "version": "11.3.6",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-11.3.6.tgz",
- "integrity": "sha512-6DxjrMKx5x68N/tCJYVYRKAtlRHbtUVBZrnAvkxbRWFD9v4vhNgsPM0RQm8i2vRugeksnao5mbnRGpS6c0awCw==",
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-12.3.0.tgz",
+ "integrity": "sha512-MgOkmrXH4zsGxhte4YqKL7d+N8ZNEd3w1wo56MZlhu5WabwCJh87wYpU5T8vyfujFLYOFuFK5jjlcbs8F4/WDw==",
"requires": {
"joi": "^17.2.1"
}
@@ -63596,7 +62630,9 @@
"requires": {}
},
"@react-native-community/netinfo": {
- "version": "9.3.10",
+ "version": "11.2.1",
+ "resolved": "https://registry.npmjs.org/@react-native-community/netinfo/-/netinfo-11.2.1.tgz",
+ "integrity": "sha512-n9kgmH7vLaU7Cdo8vGfJGGwhrlgppaOSq5zKj9I7H4k5iRM3aNtwURw83mgrc22Ip7nSye2afZV2xDiIyvHttQ==",
"requires": {}
},
"@react-native-firebase/analytics": {
@@ -63639,45 +62675,244 @@
"requires": {}
},
"@react-native-picker/picker": {
- "version": "2.4.4",
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@react-native-picker/picker/-/picker-2.5.1.tgz",
+ "integrity": "sha512-/sADUfQsosMRYtrqqL3ZYZSECRygj0fXtpRLqxJfwuMEoqfvfn40756R6B1alzusVvDRZFI0ari0iQid56hA/Q==",
"requires": {}
},
"@react-native/assets-registry": {
- "version": "0.72.0",
- "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.72.0.tgz",
- "integrity": "sha512-Im93xRJuHHxb1wniGhBMsxLwcfzdYreSZVQGDoMJgkd6+Iky61LInGEHnQCTN0fKNYF1Dvcofb4uMmE1RQHXHQ=="
+ "version": "0.73.1",
+ "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.73.1.tgz",
+ "integrity": "sha512-2FgAbU7uKM5SbbW9QptPPZx8N9Ke2L7bsHb+EhAanZjFZunA9PaYtyjUQ1s7HD+zDVqOQIvjkpXSv7Kejd2tqg=="
+ },
+ "@react-native/babel-plugin-codegen": {
+ "version": "0.73.2",
+ "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.73.2.tgz",
+ "integrity": "sha512-PadyFZWVaWXIBP7Q5dgEL7eAd7tnsgsLjoHJB1hIRZZuVUg1Zqe3nULwC7RFAqOtr5Qx7KXChkFFcKQ3WnZzGw==",
+ "requires": {
+ "@react-native/codegen": "0.73.2"
+ }
+ },
+ "@react-native/babel-preset": {
+ "version": "0.73.19",
+ "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.73.19.tgz",
+ "integrity": "sha512-ujon01uMOREZecIltQxPDmJ6xlVqAUFGI/JCSpeVYdxyXBoBH5dBb0ihj7h6LKH1q1jsnO9z4MxfddtypKkIbg==",
+ "requires": {
+ "@babel/core": "^7.20.0",
+ "@babel/plugin-proposal-async-generator-functions": "^7.0.0",
+ "@babel/plugin-proposal-class-properties": "^7.18.0",
+ "@babel/plugin-proposal-export-default-from": "^7.0.0",
+ "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.0",
+ "@babel/plugin-proposal-numeric-separator": "^7.0.0",
+ "@babel/plugin-proposal-object-rest-spread": "^7.20.0",
+ "@babel/plugin-proposal-optional-catch-binding": "^7.0.0",
+ "@babel/plugin-proposal-optional-chaining": "^7.20.0",
+ "@babel/plugin-syntax-dynamic-import": "^7.8.0",
+ "@babel/plugin-syntax-export-default-from": "^7.0.0",
+ "@babel/plugin-syntax-flow": "^7.18.0",
+ "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0",
+ "@babel/plugin-syntax-optional-chaining": "^7.0.0",
+ "@babel/plugin-transform-arrow-functions": "^7.0.0",
+ "@babel/plugin-transform-async-to-generator": "^7.20.0",
+ "@babel/plugin-transform-block-scoping": "^7.0.0",
+ "@babel/plugin-transform-classes": "^7.0.0",
+ "@babel/plugin-transform-computed-properties": "^7.0.0",
+ "@babel/plugin-transform-destructuring": "^7.20.0",
+ "@babel/plugin-transform-flow-strip-types": "^7.20.0",
+ "@babel/plugin-transform-function-name": "^7.0.0",
+ "@babel/plugin-transform-literals": "^7.0.0",
+ "@babel/plugin-transform-modules-commonjs": "^7.0.0",
+ "@babel/plugin-transform-named-capturing-groups-regex": "^7.0.0",
+ "@babel/plugin-transform-parameters": "^7.0.0",
+ "@babel/plugin-transform-private-methods": "^7.22.5",
+ "@babel/plugin-transform-private-property-in-object": "^7.22.11",
+ "@babel/plugin-transform-react-display-name": "^7.0.0",
+ "@babel/plugin-transform-react-jsx": "^7.0.0",
+ "@babel/plugin-transform-react-jsx-self": "^7.0.0",
+ "@babel/plugin-transform-react-jsx-source": "^7.0.0",
+ "@babel/plugin-transform-runtime": "^7.0.0",
+ "@babel/plugin-transform-shorthand-properties": "^7.0.0",
+ "@babel/plugin-transform-spread": "^7.0.0",
+ "@babel/plugin-transform-sticky-regex": "^7.0.0",
+ "@babel/plugin-transform-typescript": "^7.5.0",
+ "@babel/plugin-transform-unicode-regex": "^7.0.0",
+ "@babel/template": "^7.0.0",
+ "@react-native/babel-plugin-codegen": "0.73.2",
+ "babel-plugin-transform-flow-enums": "^0.0.2",
+ "react-refresh": "^0.14.0"
+ },
+ "dependencies": {
+ "react-refresh": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
+ "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ=="
+ }
+ }
},
"@react-native/codegen": {
- "version": "0.72.6",
- "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.72.6.tgz",
- "integrity": "sha512-idTVI1es/oopN0jJT/0jB6nKdvTUKE3757zA5+NPXZTeB46CIRbmmos4XBiAec8ufu9/DigLPbHTYAaMNZJ6Ig==",
+ "version": "0.73.2",
+ "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.73.2.tgz",
+ "integrity": "sha512-lfy8S7umhE3QLQG5ViC4wg5N1Z+E6RnaeIw8w1voroQsXXGPB72IBozh8dAHR3+ceTxIU0KX3A8OpJI8e1+HpQ==",
"requires": {
"@babel/parser": "^7.20.0",
"flow-parser": "^0.206.0",
+ "glob": "^7.1.1",
+ "invariant": "^2.2.4",
"jscodeshift": "^0.14.0",
+ "mkdirp": "^0.5.1",
"nullthrows": "^1.1.1"
+ },
+ "dependencies": {
+ "mkdirp": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+ "requires": {
+ "minimist": "^1.2.6"
+ }
+ }
+ }
+ },
+ "@react-native/community-cli-plugin": {
+ "version": "0.73.12",
+ "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.73.12.tgz",
+ "integrity": "sha512-xWU06OkC1cX++Duh/cD/Wv+oZ0oSY3yqbtxAqQA2H3Q+MQltNNJM6MqIHt1VOZSabRf/LVlR1JL6U9TXJirkaw==",
+ "requires": {
+ "@react-native-community/cli-server-api": "12.3.0",
+ "@react-native-community/cli-tools": "12.3.0",
+ "@react-native/dev-middleware": "0.73.7",
+ "@react-native/metro-babel-transformer": "0.73.13",
+ "chalk": "^4.0.0",
+ "execa": "^5.1.1",
+ "metro": "^0.80.3",
+ "metro-config": "^0.80.3",
+ "metro-core": "^0.80.3",
+ "node-fetch": "^2.2.0",
+ "readline": "^1.3.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "requires": {
+ "color-convert": "^2.0.1"
+ }
+ },
+ "chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "@react-native/debugger-frontend": {
+ "version": "0.73.3",
+ "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.73.3.tgz",
+ "integrity": "sha512-RgEKnWuoo54dh7gQhV7kvzKhXZEhpF9LlMdZolyhGxHsBqZ2gXdibfDlfcARFFifPIiaZ3lXuOVVa4ei+uPgTw=="
+ },
+ "@react-native/dev-middleware": {
+ "version": "0.73.7",
+ "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.73.7.tgz",
+ "integrity": "sha512-BZXpn+qKp/dNdr4+TkZxXDttfx8YobDh8MFHsMk9usouLm22pKgFIPkGBV0X8Do4LBkFNPGtrnsKkWk/yuUXKg==",
+ "requires": {
+ "@isaacs/ttlcache": "^1.4.1",
+ "@react-native/debugger-frontend": "0.73.3",
+ "chrome-launcher": "^0.15.2",
+ "chromium-edge-launcher": "^1.0.0",
+ "connect": "^3.6.5",
+ "debug": "^2.2.0",
+ "node-fetch": "^2.2.0",
+ "open": "^7.0.3",
+ "serve-static": "^1.13.1",
+ "temp-dir": "^2.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "open": {
+ "version": "7.4.2",
+ "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz",
+ "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
+ "requires": {
+ "is-docker": "^2.0.0",
+ "is-wsl": "^2.1.1"
+ }
+ }
}
},
"@react-native/gradle-plugin": {
- "version": "0.72.11",
- "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.72.11.tgz",
- "integrity": "sha512-P9iRnxiR2w7EHcZ0mJ+fmbPzMby77ZzV6y9sJI3lVLJzF7TLSdbwcQyD3lwMsiL+q5lKUHoZJS4sYmih+P2HXw=="
+ "version": "0.73.4",
+ "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.73.4.tgz",
+ "integrity": "sha512-PMDnbsZa+tD55Ug+W8CfqXiGoGneSSyrBZCMb5JfiB3AFST3Uj5e6lw8SgI/B6SKZF7lG0BhZ6YHZsRZ5MlXmg=="
},
"@react-native/js-polyfills": {
- "version": "0.72.1",
- "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.72.1.tgz",
- "integrity": "sha512-cRPZh2rBswFnGt5X5EUEPs0r+pAsXxYsifv/fgy9ZLQokuT52bPH+9xjDR+7TafRua5CttGW83wP4TntRcWNDA=="
+ "version": "0.73.1",
+ "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.73.1.tgz",
+ "integrity": "sha512-ewMwGcumrilnF87H4jjrnvGZEaPFCAC4ebraEK+CurDDmwST/bIicI4hrOAv+0Z0F7DEK4O4H7r8q9vH7IbN4g=="
+ },
+ "@react-native/metro-babel-transformer": {
+ "version": "0.73.13",
+ "resolved": "https://registry.npmjs.org/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.73.13.tgz",
+ "integrity": "sha512-k9AQifogQfgUXPlqQSoMtX2KUhniw4XvJl+nZ4hphCH7qiMDAwuP8OmkJbz5E/N+Ro9OFuLE7ax4GlwxaTsAWg==",
+ "requires": {
+ "@babel/core": "^7.20.0",
+ "@react-native/babel-preset": "0.73.19",
+ "hermes-parser": "0.15.0",
+ "nullthrows": "^1.1.1"
+ }
},
"@react-native/metro-config": {
- "version": "0.72.11",
- "resolved": "https://registry.npmjs.org/@react-native/metro-config/-/metro-config-0.72.11.tgz",
- "integrity": "sha512-661EyQnDdVelyc0qP/ew7kKkGAh6N6KlkuPLC2SQ8sxaXskVU6fSuNlpLW4bUTBUDFKG8gEOU2hp6rzk4wQnGQ==",
+ "version": "0.73.3",
+ "resolved": "https://registry.npmjs.org/@react-native/metro-config/-/metro-config-0.73.3.tgz",
+ "integrity": "sha512-aIVh+lM52n7/RFDXLDiIp1vI21jc9thm2VxdkP7KwxMut7VvW+2tO38zKt74/2ker2ca0205tbf3pyCYBvV6Ww==",
"dev": true,
"requires": {
- "@react-native/js-polyfills": "^0.72.1",
- "metro-config": "0.76.8",
- "metro-react-native-babel-transformer": "0.76.8",
- "metro-runtime": "0.76.8"
+ "@react-native/js-polyfills": "0.73.1",
+ "@react-native/metro-babel-transformer": "0.73.13",
+ "metro-config": "^0.80.3",
+ "metro-runtime": "^0.80.3"
}
},
"@react-native/normalize-color": {
@@ -63686,14 +62921,14 @@
"integrity": "sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA=="
},
"@react-native/normalize-colors": {
- "version": "0.72.0",
- "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.72.0.tgz",
- "integrity": "sha512-285lfdqSXaqKuBbbtP9qL2tDrfxdOFtIMvkKadtleRQkdOxx+uzGvFr82KHmc/sSiMtfXGp7JnFYWVh4sFl7Yw=="
+ "version": "0.73.2",
+ "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.73.2.tgz",
+ "integrity": "sha512-bRBcb2T+I88aG74LMVHaKms2p/T8aQd8+BZ7LuuzXlRfog1bMWWn/C5i0HVuvW4RPtXQYgIlGiXVDy9Ir1So/w=="
},
"@react-native/virtualized-lists": {
- "version": "0.72.8",
- "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.72.8.tgz",
- "integrity": "sha512-J3Q4Bkuo99k7mu+jPS9gSUSgq+lLRSI/+ahXNwV92XgJ/8UgOTxu2LPwhJnBk/sQKxq7E8WkZBnBiozukQMqrw==",
+ "version": "0.73.4",
+ "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.73.4.tgz",
+ "integrity": "sha512-HpmLg1FrEiDtrtAbXiwCgXFYyloK/dOIPIuWW3fsqukwJEWAiTzm1nXGJ7xPU5XTHiWZ4sKup5Ebaj8z7iyWog==",
"requires": {
"invariant": "^2.2.4",
"nullthrows": "^1.1.1"
@@ -63798,6 +63033,107 @@
}
}
},
+ "@remix-run/node": {
+ "version": "1.19.3",
+ "resolved": "https://registry.npmjs.org/@remix-run/node/-/node-1.19.3.tgz",
+ "integrity": "sha512-z5qrVL65xLXIUpU4mkR4MKlMeKARLepgHAk4W5YY3IBXOreRqOGUC70POViYmY7x38c2Ia1NwqL80H+0h7jbMw==",
+ "requires": {
+ "@remix-run/server-runtime": "1.19.3",
+ "@remix-run/web-fetch": "^4.3.6",
+ "@remix-run/web-file": "^3.0.3",
+ "@remix-run/web-stream": "^1.0.4",
+ "@web3-storage/multipart-parser": "^1.0.0",
+ "abort-controller": "^3.0.0",
+ "cookie-signature": "^1.1.0",
+ "source-map-support": "^0.5.21",
+ "stream-slice": "^0.1.2"
+ },
+ "dependencies": {
+ "cookie-signature": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.1.tgz",
+ "integrity": "sha512-78KWk9T26NhzXtuL26cIJ8/qNHANyJ/ZYrmEXFzUmhZdjpBv+DlWlOANRTGBt48YcyslsLrj0bMLFTmXvLRCOw=="
+ }
+ }
+ },
+ "@remix-run/router": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.7.2.tgz",
+ "integrity": "sha512-7Lcn7IqGMV+vizMPoEl5F0XDshcdDYtMI6uJLQdQz5CfZAwy3vvGKYSUk789qndt5dEC4HfSjviSYlSoHGL2+A=="
+ },
+ "@remix-run/server-runtime": {
+ "version": "1.19.3",
+ "resolved": "https://registry.npmjs.org/@remix-run/server-runtime/-/server-runtime-1.19.3.tgz",
+ "integrity": "sha512-KzQ+htUsKqpBgKE2tWo7kIIGy3MyHP58Io/itUPvV+weDjApwr9tQr9PZDPA3yAY6rAzLax7BU0NMSYCXWFY5A==",
+ "requires": {
+ "@remix-run/router": "1.7.2",
+ "@types/cookie": "^0.4.1",
+ "@web3-storage/multipart-parser": "^1.0.0",
+ "cookie": "^0.4.1",
+ "set-cookie-parser": "^2.4.8",
+ "source-map": "^0.7.3"
+ },
+ "dependencies": {
+ "cookie": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
+ "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA=="
+ },
+ "source-map": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
+ "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA=="
+ }
+ }
+ },
+ "@remix-run/web-blob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@remix-run/web-blob/-/web-blob-3.1.0.tgz",
+ "integrity": "sha512-owGzFLbqPH9PlKb8KvpNJ0NO74HWE2euAn61eEiyCXX/oteoVzTVSN8mpLgDjaxBf2btj5/nUllSUgpyd6IH6g==",
+ "requires": {
+ "@remix-run/web-stream": "^1.1.0",
+ "web-encoding": "1.1.5"
+ }
+ },
+ "@remix-run/web-fetch": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/@remix-run/web-fetch/-/web-fetch-4.4.2.tgz",
+ "integrity": "sha512-jgKfzA713/4kAW/oZ4bC3MoLWyjModOVDjFPNseVqcJKSafgIscrYL9G50SurEYLswPuoU3HzSbO0jQCMYWHhA==",
+ "requires": {
+ "@remix-run/web-blob": "^3.1.0",
+ "@remix-run/web-file": "^3.1.0",
+ "@remix-run/web-form-data": "^3.1.0",
+ "@remix-run/web-stream": "^1.1.0",
+ "@web3-storage/multipart-parser": "^1.0.0",
+ "abort-controller": "^3.0.0",
+ "data-uri-to-buffer": "^3.0.1",
+ "mrmime": "^1.0.0"
+ }
+ },
+ "@remix-run/web-file": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@remix-run/web-file/-/web-file-3.1.0.tgz",
+ "integrity": "sha512-dW2MNGwoiEYhlspOAXFBasmLeYshyAyhIdrlXBi06Duex5tDr3ut2LFKVj7tyHLmn8nnNwFf1BjNbkQpygC2aQ==",
+ "requires": {
+ "@remix-run/web-blob": "^3.1.0"
+ }
+ },
+ "@remix-run/web-form-data": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@remix-run/web-form-data/-/web-form-data-3.1.0.tgz",
+ "integrity": "sha512-NdeohLMdrb+pHxMQ/Geuzdp0eqPbea+Ieo8M8Jx2lGC6TBHsgHzYcBvr0LyPdPVycNRDEpWpiDdCOdCryo3f9A==",
+ "requires": {
+ "web-encoding": "1.1.5"
+ }
+ },
+ "@remix-run/web-stream": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@remix-run/web-stream/-/web-stream-1.1.0.tgz",
+ "integrity": "sha512-KRJtwrjRV5Bb+pM7zxcTJkhIqWWSy+MYsIxHK+0m5atcznsf15YwUBWHWulZerV2+vvHH1Lp1DD7pw6qKW8SgA==",
+ "requires": {
+ "web-streams-polyfill": "^3.1.1"
+ }
+ },
"@rnmapbox/maps": {
"version": "10.0.11",
"resolved": "https://registry.npmjs.org/@rnmapbox/maps/-/maps-10.0.11.tgz",
@@ -63878,9 +63214,9 @@
}
},
"@shopify/flash-list": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/@shopify/flash-list/-/flash-list-1.6.1.tgz",
- "integrity": "sha512-SlBlpP7+zol6D1SKaf402aS30Qgwdjwb8/Qn2CupYwXnTcu2l8TiXB766vcsIvKTqUO7ELfQnCwCq8NXx55FsQ==",
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/@shopify/flash-list/-/flash-list-1.6.3.tgz",
+ "integrity": "sha512-XM2iu4CeD9SOEUxaGG3UkxfUxGPWG9yacga1yQSgskAjUsRDFTsD3y4Dyon9n8MfDwgrRpEwuijd+7NeQQoWaQ==",
"requires": {
"recyclerlistview": "4.2.0",
"tslib": "2.4.0"
@@ -71204,6 +70540,12 @@
"@types/responselike": "^1.0.0"
}
},
+ "@types/canvas-size": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@types/canvas-size/-/canvas-size-1.2.2.tgz",
+ "integrity": "sha512-yuTXFWC4tHV3lt5ZtbIP9VeeMNbDYm5mPyqaQnaMuSSx2mjsfZGXMNmHTnfdsR5qZdB6dtbaV5IP2PKv79vmKg==",
+ "dev": true
+ },
"@types/concurrently": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@types/concurrently/-/concurrently-7.0.0.tgz",
@@ -71230,6 +70572,11 @@
"@types/node": "*"
}
},
+ "@types/cookie": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
+ "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
+ },
"@types/debug": {
"version": "4.1.8",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz",
@@ -71617,9 +70964,9 @@
"dev": true
},
"@types/react": {
- "version": "18.2.12",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.12.tgz",
- "integrity": "sha512-ndmBMLCgn38v3SntMeoJaIrO6tGHYKMEBohCUmw8HoLLQdRMOIGXfeYaBTLe2lsFaSB3MOK1VXscYFnmLtTSmw==",
+ "version": "18.2.45",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.45.tgz",
+ "integrity": "sha512-TtAxCNrlrBp8GoeEp1npd5g+d/OejJHFxS3OWmrPBMFaVQMSN0OFySozJio5BHxTuTeug00AVXVAjfDSfk+lUg==",
"requires": {
"@types/prop-types": "*",
"@types/scheduler": "*",
@@ -72251,6 +71598,11 @@
"integrity": "sha512-RoorRB50WehYbsiWu497q8egZBYlrvOo9KBUG41uth4O023Cbs+7POLm9uw2CAiViBAIhvpw1Y4w4i+MZxOfXw==",
"requires": {}
},
+ "@web3-storage/multipart-parser": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@web3-storage/multipart-parser/-/multipart-parser-1.0.0.tgz",
+ "integrity": "sha512-BEO6al7BYqcnfX15W2cnGR+Q566ACXAT9UQykORCWW80lmkpWsnEob6zJS1ZVBKsSJC8+7vJkHwlp+lXG1UCdw=="
+ },
"@webassemblyjs/ast": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz",
@@ -72591,6 +71943,12 @@
"resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz",
"integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ=="
},
+ "@zxing/text-encoding": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz",
+ "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==",
+ "optional": true
+ },
"7zip-bin": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.1.1.tgz",
@@ -73782,6 +73140,7 @@
},
"babel-plugin-module-resolver": {
"version": "5.0.0",
+ "dev": true,
"requires": {
"find-babel-config": "^2.0.0",
"glob": "^8.0.3",
@@ -73792,6 +73151,7 @@
"dependencies": {
"brace-expansion": {
"version": "2.0.1",
+ "dev": true,
"requires": {
"balanced-match": "^1.0.0"
}
@@ -73800,6 +73160,7 @@
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
"integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
+ "dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
@@ -73812,6 +73173,7 @@
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "dev": true,
"requires": {
"brace-expansion": "^2.0.1"
}
@@ -73947,18 +73309,26 @@
}
},
"babel-preset-expo": {
- "version": "9.5.2",
- "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-9.5.2.tgz",
- "integrity": "sha512-hU1G1TDiikuXV6UDZjPnX+WdbjbtidDiYhftMEVrZQSst45pDPVBWbM41TUKrpJMwv4FypsLzK+378gnMPRVWQ==",
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-10.0.1.tgz",
+ "integrity": "sha512-uWIGmLfbP3dS5+8nesxaW6mQs41d4iP7X82ZwRdisB/wAhKQmuJM9Y1jQe4006uNYkw6Phf2TT03ykLVro7KuQ==",
"requires": {
"@babel/plugin-proposal-decorators": "^7.12.9",
- "@babel/plugin-proposal-export-namespace-from": "^7.18.9",
- "@babel/plugin-proposal-object-rest-spread": "^7.12.13",
- "@babel/plugin-transform-react-jsx": "^7.12.17",
+ "@babel/plugin-transform-export-namespace-from": "^7.22.11",
+ "@babel/plugin-transform-object-rest-spread": "^7.12.13",
+ "@babel/plugin-transform-parameters": "^7.22.15",
"@babel/preset-env": "^7.20.0",
- "babel-plugin-module-resolver": "^5.0.0",
+ "@babel/preset-react": "^7.22.15",
+ "@react-native/babel-preset": "^0.73.18",
"babel-plugin-react-native-web": "~0.18.10",
- "metro-react-native-babel-preset": "0.76.8"
+ "react-refresh": "0.14.0"
+ },
+ "dependencies": {
+ "react-refresh": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
+ "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ=="
+ }
}
},
"babel-preset-fbjs": {
@@ -74144,6 +73514,11 @@
"resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz",
"integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA=="
},
+ "base64-arraybuffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
+ "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ=="
+ },
"base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -75120,11 +74495,35 @@
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="
},
+ "chrome-launcher": {
+ "version": "0.15.2",
+ "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz",
+ "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==",
+ "requires": {
+ "@types/node": "*",
+ "escape-string-regexp": "^4.0.0",
+ "is-wsl": "^2.2.0",
+ "lighthouse-logger": "^1.0.0"
+ }
+ },
"chrome-trace-event": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
"integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg=="
},
+ "chromium-edge-launcher": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-1.0.0.tgz",
+ "integrity": "sha512-pgtgjNKZ7i5U++1g1PWv75umkHvhVTDOQIZ+sjeUX9483S7Y6MUvO0lrd7ShGlQlFHMN4SwKTCq/X8hWrbv2KA==",
+ "requires": {
+ "@types/node": "*",
+ "escape-string-regexp": "^4.0.0",
+ "is-wsl": "^2.2.0",
+ "lighthouse-logger": "^1.0.0",
+ "mkdirp": "^1.0.4",
+ "rimraf": "^3.0.2"
+ }
+ },
"chromium-pickle-js": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz",
@@ -75275,9 +74674,9 @@
}
},
"cli-spinners": {
- "version": "2.9.1",
- "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.1.tgz",
- "integrity": "sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ=="
+ "version": "2.9.2",
+ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz",
+ "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="
},
"cli-table3": {
"version": "0.6.3",
@@ -75307,9 +74706,9 @@
"dev": true
},
"clipboard": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.4.tgz",
- "integrity": "sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==",
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz",
+ "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==",
"requires": {
"good-listener": "^1.2.2",
"select": "^1.1.2",
@@ -75548,11 +74947,6 @@
"integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==",
"dev": true
},
- "compare-versions": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz",
- "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA=="
- },
"complex.js": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.1.1.tgz",
@@ -75566,9 +74960,9 @@
"devOptional": true
},
"component-type": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/component-type/-/component-type-1.2.1.tgz",
- "integrity": "sha512-Kgy+2+Uwr75vAi6ChWXgHuLvd+QLD7ssgpaRq2zCvt80ptvAfMc/hijcJxXkBa2wMlEZcJvC2H8Ubo+A9ATHIg=="
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/component-type/-/component-type-1.2.2.tgz",
+ "integrity": "sha512-99VUHREHiN5cLeHm3YLq312p6v+HUEcwtLCAtelvUDI6+SH5g5Cr85oNR2S1o6ywzL0ykMbuwLzM2ANocjEOIA=="
},
"compressible": {
"version": "2.0.18",
@@ -76366,6 +75760,14 @@
"isobject": "^3.0.1"
}
},
+ "css-line-break": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
+ "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
+ "requires": {
+ "utrie": "^1.0.2"
+ }
+ },
"css-loader": {
"version": "6.8.1",
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz",
@@ -76581,6 +75983,11 @@
"integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
"dev": true
},
+ "data-uri-to-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz",
+ "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og=="
+ },
"data-urls": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz",
@@ -77236,8 +76643,7 @@
"eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
- "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
- "dev": true
+ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
},
"ee-first": {
"version": "1.1.1",
@@ -77612,7 +77018,9 @@
"dev": true
},
"envinfo": {
- "version": "7.8.1"
+ "version": "7.11.0",
+ "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.0.tgz",
+ "integrity": "sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg=="
},
"eol": {
"version": "0.9.1",
@@ -79259,36 +78667,26 @@
}
},
"expensify-common": {
- "version": "git+ssh://git@github.com/Expensify/expensify-common.git#398bf7c6a6d37f229a41d92bd7a4324c0fd32849",
- "integrity": "sha512-H7UrLgWIr8mCoPc1oxbeYW2RwLzUWI6jdjbV6cRnrlp8cDW3IyZISF+BQSPFDj7bMhNAbczQPtEOE1gld21Cvg==",
- "from": "expensify-common@git+ssh://git@github.com/Expensify/expensify-common.git#398bf7c6a6d37f229a41d92bd7a4324c0fd32849",
+ "version": "git+ssh://git@github.com/Expensify/expensify-common.git#c6bb3cfa56d12af9fa02e2bfc729646f5b64ef44",
+ "integrity": "sha512-a/UBkrerB57nB9xbBrFIeJG3IN0lVZV+/JWNbGMfT0FHxtg8/4sGWdC+AHqR3Bm01gwt67dd2csFferlZmTIsg==",
+ "from": "expensify-common@git+ssh://git@github.com/Expensify/expensify-common.git#c6bb3cfa56d12af9fa02e2bfc729646f5b64ef44",
"requires": {
"classnames": "2.3.1",
- "clipboard": "2.0.4",
- "html-entities": "^2.3.3",
+ "clipboard": "2.0.11",
+ "html-entities": "^2.4.0",
"jquery": "3.6.0",
"localforage": "^1.10.0",
"lodash": "4.17.21",
- "prop-types": "15.7.2",
+ "prop-types": "15.8.1",
"react": "16.12.0",
"react-dom": "16.12.0",
- "semver": "^7.3.5",
+ "semver": "^7.5.2",
"simply-deferred": "git+https://github.com/Expensify/simply-deferred.git#77a08a95754660c7bd6e0b6979fdf84e8e831bf5",
- "string.prototype.replaceall": "^1.0.6",
+ "string.prototype.replaceall": "^1.0.8",
"ua-parser-js": "^1.0.35",
"underscore": "1.13.6"
},
"dependencies": {
- "prop-types": {
- "version": "15.7.2",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
- "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
- "requires": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.8.1"
- }
- },
"react": {
"version": "16.12.0",
"resolved": "https://registry.npmjs.org/react/-/react-16.12.0.tgz",
@@ -79327,30 +78725,25 @@
}
},
"expo": {
- "version": "49.0.21",
- "resolved": "https://registry.npmjs.org/expo/-/expo-49.0.21.tgz",
- "integrity": "sha512-JpHL6V0yt8/fzsmkAdPdtsah+lU6Si4ac7MDklLYvzEil7HAFEsN/pf06wQ21ax4C+BL27hI6JJoD34tzXUCJA==",
+ "version": "50.0.0-preview.7",
+ "resolved": "https://registry.npmjs.org/expo/-/expo-50.0.0-preview.7.tgz",
+ "integrity": "sha512-FyoEJVf42Tr1On0IFa0dL7Qs9gnl252ah3e0B8FsU96G7Hi93cDz5Rcn81ezRiO6YIF4nFV3+bh6BHsm/nsA0A==",
"requires": {
"@babel/runtime": "^7.20.0",
- "@expo/cli": "0.10.16",
- "@expo/config": "8.1.2",
- "@expo/config-plugins": "7.2.5",
+ "@expo/cli": "0.16.5",
+ "@expo/config": "8.5.2",
+ "@expo/config-plugins": "7.8.2",
+ "@expo/metro-config": "0.17.1",
"@expo/vector-icons": "^13.0.0",
- "babel-preset-expo": "~9.5.2",
- "expo-application": "~5.3.0",
- "expo-asset": "~8.10.1",
- "expo-constants": "~14.4.2",
- "expo-file-system": "~15.4.5",
- "expo-font": "~11.4.0",
- "expo-keep-awake": "~12.3.0",
- "expo-modules-autolinking": "1.5.1",
- "expo-modules-core": "1.5.12",
+ "babel-preset-expo": "~10.0.1",
+ "expo-asset": "~9.0.1",
+ "expo-file-system": "~16.0.2",
+ "expo-font": "~11.10.0",
+ "expo-keep-awake": "~12.8.0",
+ "expo-modules-autolinking": "1.9.0",
+ "expo-modules-core": "1.11.4",
"fbemitter": "^3.0.0",
- "invariant": "^2.2.4",
- "md5-file": "^3.2.3",
- "node-fetch": "^2.6.7",
- "pretty-format": "^26.5.2",
- "uuid": "^3.4.0"
+ "whatwg-url-without-unicode": "8.0.0-3"
},
"dependencies": {
"@babel/code-frame": {
@@ -79362,13 +78755,14 @@
}
},
"@expo/config-plugins": {
- "version": "7.2.5",
- "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.2.5.tgz",
- "integrity": "sha512-w+5ccu1IxBHgyQk9CPFKLZOk8yZQEyTjbJwOzESK1eR7QwosbcsLkN1c1WWUZYiCXwORu3UTwJYll4+X2xxJhQ==",
- "requires": {
- "@expo/config-types": "^49.0.0-alpha.1",
- "@expo/json-file": "~8.2.37",
- "@expo/plist": "^0.0.20",
+ "version": "7.8.2",
+ "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.8.2.tgz",
+ "integrity": "sha512-XM2eXA5EvcpmXFCui48+bVy8GTskYSjPf2yC+LliYv8PDcedu7+pdgmbnvH4eZCyHfTMO8/UiF+w8e5WgOEj5A==",
+ "requires": {
+ "@expo/config-types": "^50.0.0-alpha.1",
+ "@expo/fingerprint": "^0.6.0",
+ "@expo/json-file": "~8.3.0",
+ "@expo/plist": "^0.1.0",
"@expo/sdk-runtime-versions": "^1.0.0",
"@react-native/normalize-color": "^2.0.0",
"chalk": "^4.1.2",
@@ -79379,19 +78773,20 @@
"resolve-from": "^5.0.0",
"semver": "^7.5.3",
"slash": "^3.0.0",
+ "slugify": "^1.6.6",
"xcode": "^3.0.1",
"xml2js": "0.6.0"
}
},
"@expo/config-types": {
- "version": "49.0.0",
- "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-49.0.0.tgz",
- "integrity": "sha512-8eyREVi+K2acnMBe/rTIu1dOfyR2+AMnTLHlut+YpMV9OZPdeKV0Bs9BxAewGqBA2slslbQ9N39IS2CuTKpXkA=="
+ "version": "50.0.0",
+ "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-50.0.0.tgz",
+ "integrity": "sha512-0kkhIwXRT6EdFDwn+zTg9R2MZIAEYGn1MVkyRohAd+C9cXOb5RA8WLQi7vuxKF9m1SMtNAUrf0pO+ENK0+/KSw=="
},
"@expo/json-file": {
- "version": "8.2.37",
- "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.2.37.tgz",
- "integrity": "sha512-YaH6rVg11JoTS2P6LsW7ybS2CULjf40AbnAHw2F1eDPuheprNjARZMnyHFPkKv7GuxCy+B9GPcbOKgc4cgA80Q==",
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.3.0.tgz",
+ "integrity": "sha512-yROUeXJXR5goagB8c3muFLCzLmdGOvoPpR5yDNaXrnTp4euNykr9yW0wWhJx4YVRTNOPtGBnEbbJBW+a9q+S6g==",
"requires": {
"@babel/code-frame": "~7.10.4",
"json5": "^2.2.2",
@@ -79399,20 +78794,15 @@
}
},
"@expo/plist": {
- "version": "0.0.20",
- "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.0.20.tgz",
- "integrity": "sha512-UXQ4LXCfTZ580LDHGJ5q62jSTwJFFJ1GqBu8duQMThiHKWbMJ+gajJh6rsB6EJ3aLUr9wcauxneL5LVRFxwBEA==",
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.1.0.tgz",
+ "integrity": "sha512-xWD+8vIFif0wKyuqe3fmnmnSouXYucciZXFzS0ZD5OV9eSAS1RGQI5FaGGJ6zxJ4mpdy/4QzbLdBjnYE5vxA0g==",
"requires": {
"@xmldom/xmldom": "~0.7.7",
"base64-js": "^1.2.3",
"xmlbuilder": "^14.0.0"
}
},
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
- },
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@@ -79448,22 +78838,6 @@
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
},
- "pretty-format": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz",
- "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==",
- "requires": {
- "@jest/types": "^26.6.2",
- "ansi-regex": "^5.0.0",
- "ansi-styles": "^4.0.0",
- "react-is": "^17.0.1"
- }
- },
- "react-is": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
- "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
- },
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -79472,11 +78846,6 @@
"has-flag": "^4.0.0"
}
},
- "uuid": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
- "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
- },
"xml2js": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.0.tgz",
@@ -79495,90 +78864,61 @@
}
}
},
- "expo-application": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/expo-application/-/expo-application-5.3.1.tgz",
- "integrity": "sha512-HR2+K+Hm33vLw/TfbFaHrvUbRRNRco8R+3QaCKy7eJC2LFfT05kZ15ynGaKfB5DJ/oqPV3mxXVR/EfwmE++hoA==",
- "requires": {}
- },
"expo-asset": {
- "version": "8.10.1",
- "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-8.10.1.tgz",
- "integrity": "sha512-5VMTESxgY9GBsspO/esY25SKEa7RyascVkLe/OcL1WgblNFm7xCCEEUIW8VWS1nHJQGYxpMZPr3bEfjMpdWdyA==",
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-9.0.1.tgz",
+ "integrity": "sha512-hoCzQ8ga6ZOmkwABQeAIStXmshpK+1oNpGNNeJCJ1QdoU6hlCu6DKnikreLZYr6FQzaQTS3yel86zuRQtwNpaQ==",
"requires": {
+ "@react-native/assets-registry": "~0.73.1",
"blueimp-md5": "^2.10.0",
- "expo-constants": "~14.4.2",
- "expo-file-system": "~15.4.0",
+ "expo-constants": "~15.4.0",
+ "expo-file-system": "~16.0.0",
"invariant": "^2.2.4",
- "md5-file": "^3.2.3",
- "path-browserify": "^1.0.0",
- "url-parse": "^1.5.9"
- },
- "dependencies": {
- "path-browserify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
- "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="
- }
+ "md5-file": "^3.2.3"
}
},
"expo-constants": {
- "version": "14.4.2",
- "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-14.4.2.tgz",
- "integrity": "sha512-nOB122DOAjk+KrJT69lFQAoYVQGQjFHSigCPVBzVdko9S1xGsfiOH9+X5dygTsZTIlVLpQJDdmZ7ONiv3i+26w==",
+ "version": "15.4.2",
+ "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-15.4.2.tgz",
+ "integrity": "sha512-goJ44MsjRkJQbi/w49n7HIsBnp7Caa4mPMDUgTwk07BCUM5yKPb3Ny2/0QsaUcqBNgke2IXxr4OhqDYLd1jWOQ==",
"requires": {
- "@expo/config": "~8.1.0",
- "uuid": "^3.3.2"
- },
- "dependencies": {
- "uuid": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
- "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
- }
+ "@expo/config": "~8.5.0"
}
},
"expo-file-system": {
- "version": "15.4.5",
- "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-15.4.5.tgz",
- "integrity": "sha512-xy61KaTaDgXhT/dllwYDHm3ch026EyO8j4eC6wSVr/yE12MMMxAC09yGwy4f7kkOs6ztGVQF5j7ldRzNLN4l0Q==",
- "requires": {
- "uuid": "^3.4.0"
- },
- "dependencies": {
- "uuid": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
- "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
- }
- }
+ "version": "16.0.2",
+ "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-16.0.2.tgz",
+ "integrity": "sha512-oqiM3aq4mGugdv6DRH0wjrULWdZFm4EMLgKmR24on/f9ZCDG9VB3waSy+9J3XaDTAXBaB9ta82ACnNzk8KPdMw==",
+ "requires": {}
},
"expo-font": {
- "version": "11.4.0",
- "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-11.4.0.tgz",
- "integrity": "sha512-nkmezCFD7gR/I6R+e3/ry18uEfF8uYrr6h+PdBJu+3dawoLOpo+wFb/RG9bHUekU1/cPanR58LR7G5MEMKHR2w==",
+ "version": "11.10.0",
+ "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-11.10.0.tgz",
+ "integrity": "sha512-yqlsoOKWiYv8aBMFqheHSUKKEY/lrB7zHjzDc60OF1xGa1q8kh7mKQVwSaRMS0G77GEUvvk8Vb/uKw51KY1kGA==",
"requires": {
"fontfaceobserver": "^2.1.0"
}
},
"expo-image": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/expo-image/-/expo-image-1.8.1.tgz",
- "integrity": "sha512-YHoP3F6zRcI9ULjB84jPt62ggSrdGLtpSxZTUxwmfI+WfuucNd/zqqXx0edsCyREIA6VvoyWBT48BBgvi+H1TA==",
- "requires": {}
+ "version": "1.10.1",
+ "resolved": "https://registry.npmjs.org/expo-image/-/expo-image-1.10.1.tgz",
+ "integrity": "sha512-NwJt2FS6sZXeP92RpsZxBKSnCPWMdcJ2Q2bXHc8WgOkLLInvRd0yBKAzEusXTZ6+N+RqAcWVojlh3EBbSQhkiA==",
+ "requires": {
+ "@react-native/assets-registry": "~0.73.1"
+ }
},
"expo-keep-awake": {
- "version": "12.3.0",
- "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-12.3.0.tgz",
- "integrity": "sha512-ujiJg1p9EdCOYS05jh5PtUrfiZnK0yyLy+UewzqrjUqIT8eAGMQbkfOn3C3fHE7AKd5AefSMzJnS3lYZcZYHDw==",
+ "version": "12.8.0",
+ "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-12.8.0.tgz",
+ "integrity": "sha512-KMk9nnOEEI2w4aYr/PMnLT6ryXwmHfsb/baeHX/RSLNBZ4a5JVkNXP+mT66UNnYfXxy3pABruusd7KjeKW+F0A==",
"requires": {}
},
"expo-modules-autolinking": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-1.5.1.tgz",
- "integrity": "sha512-yt5a1VCp2BF9CrsO689PCD5oXKP14MMhnOanQMvDn4BDpURYfzAlDVGC5fZrNQKtwn/eq3bcrxIwZ7D9QjVVRg==",
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-1.9.0.tgz",
+ "integrity": "sha512-FVRuclmR7w6FZRXZmTwPdIr9PNCP7FUWMhpzaxbKU/xm7DbNw5ORAv2gaM8t9OaMxYjIAMSNYi0NnmLIinzBKA==",
"requires": {
- "@expo/config": "~8.1.0",
+ "@expo/config": "~8.5.0",
"chalk": "^4.1.0",
"commander": "^7.2.0",
"fast-glob": "^3.2.5",
@@ -79637,11 +78977,10 @@
}
},
"expo-modules-core": {
- "version": "1.5.12",
- "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-1.5.12.tgz",
- "integrity": "sha512-mY4wTDU458dhwk7IVxLNkePlYXjs9BTgk4NQHBUXf0LapXsvr+i711qPZaFNO4egf5qq6fQV+Yfd/KUguHstnQ==",
+ "version": "1.11.4",
+ "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-1.11.4.tgz",
+ "integrity": "sha512-MeDvWvdI3cHJO2VsASXsNYVoou1sdEO/SGBdLh2lxRhNpCLB0IIEZ3uPZwQQ8WBfFyPk4QT7M3XhCdPCKaT21A==",
"requires": {
- "compare-versions": "^3.4.0",
"invariant": "^2.2.4"
}
},
@@ -79881,9 +79220,9 @@
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="
},
"fast-xml-parser": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.1.tgz",
- "integrity": "sha512-viVv3xb8D+SiS1W4cv4tva3bni08kAkx0gQnWrykMM8nXPc1FxqZPU00dCEVjkiCg4HoXd2jC4x29Nzg/l2DAA==",
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.2.tgz",
+ "integrity": "sha512-rmrXUXwbJedoXkStenj1kkljNF7ugn5ZjR9FJcwmCfcCbtOMDghPajbc+Tck6vE6F5XsDmx+Pr2le9fw8+pXBg==",
"requires": {
"strnum": "^1.0.5"
}
@@ -80109,13 +79448,15 @@
},
"find-babel-config": {
"version": "2.0.0",
+ "dev": true,
"requires": {
"json5": "^2.1.1",
"path-exists": "^4.0.0"
},
"dependencies": {
"path-exists": {
- "version": "4.0.0"
+ "version": "4.0.0",
+ "dev": true
}
}
},
@@ -80213,9 +79554,9 @@
"dev": true
},
"flow-enums-runtime": {
- "version": "0.0.5",
- "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.5.tgz",
- "integrity": "sha512-PSZF9ZuaZD03sT9YaIs0FrGJ7lSUw7rHZIex+73UYVXg46eL/wxN5PaVcPJFudE2cJu5f0fezitV5aBkLHPUOQ=="
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz",
+ "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw=="
},
"flow-parser": {
"version": "0.206.0",
@@ -81183,16 +80524,16 @@
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
},
"hermes-estree": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.12.0.tgz",
- "integrity": "sha512-+e8xR6SCen0wyAKrMT3UD0ZCCLymKhRgjEB5sS28rKiFir/fXgLoeRilRUssFCILmGHb+OvHDUlhxs0+IEyvQw=="
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.15.0.tgz",
+ "integrity": "sha512-lLYvAd+6BnOqWdnNbP/Q8xfl8LOGw4wVjfrNd9Gt8eoFzhNBRVD95n4l2ksfMVOoxuVyegs85g83KS9QOsxbVQ=="
},
"hermes-parser": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.12.0.tgz",
- "integrity": "sha512-d4PHnwq6SnDLhYl3LHNHvOg7nQ6rcI7QVil418REYksv0Mh3cEkHDcuhGxNQ3vgnLSLl4QSvDrFCwQNYdpWlzw==",
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.15.0.tgz",
+ "integrity": "sha512-Q1uks5rjZlE9RjMMjSUCkGrEIPI5pKJILeCtK1VmTj7U4pf3wVPoo+cxfu+s4cBAPy2JzikIIdCZgBoR6x7U1Q==",
"requires": {
- "hermes-estree": "0.12.0"
+ "hermes-estree": "0.15.0"
}
},
"hermes-profile-transformer": {
@@ -81270,9 +80611,9 @@
}
},
"html-entities": {
- "version": "2.3.5",
- "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.5.tgz",
- "integrity": "sha512-72TJlcMkYsEJASa/3HnX7VT59htM7iSHbH59NSZbtc+22Ap0Txnlx91sfeB+/A7wNZg7UxtZdhAW4y+/jimrdg=="
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz",
+ "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ=="
},
"html-escaper": {
"version": "2.0.2",
@@ -81329,6 +80670,15 @@
}
}
},
+ "html2canvas": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
+ "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
+ "requires": {
+ "css-line-break": "^2.1.0",
+ "text-segmentation": "^1.0.3"
+ }
+ },
"htmlparser2": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz",
@@ -81718,9 +81068,9 @@
"integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ=="
},
"image-size": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz",
- "integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.1.1.tgz",
+ "integrity": "sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==",
"requires": {
"queue": "6.0.2"
}
@@ -82097,7 +81447,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
- "dev": true,
"requires": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
@@ -82293,7 +81642,6 @@
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
"integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
- "dev": true,
"requires": {
"has-tostringtag": "^1.0.0"
}
@@ -82678,10 +82026,9 @@
}
},
"jackspeak": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.1.tgz",
- "integrity": "sha512-MXbxovZ/Pm42f6cDIDkl3xpwv1AGwObKwfmjs2nQePiy85tP3fatofl3FC1aBsOtP/6fq5SbtgHwWcMsLP+bDw==",
- "dev": true,
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz",
+ "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==",
"requires": {
"@isaacs/cliui": "^8.0.2",
"@pkgjs/parseargs": "^0.11.0"
@@ -83362,20 +82709,24 @@
}
},
"jest-environment-node": {
- "version": "29.4.1",
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz",
+ "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==",
"requires": {
- "@jest/environment": "^29.4.1",
- "@jest/fake-timers": "^29.4.1",
- "@jest/types": "^29.4.1",
+ "@jest/environment": "^29.7.0",
+ "@jest/fake-timers": "^29.7.0",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
- "jest-mock": "^29.4.1",
- "jest-util": "^29.4.1"
+ "jest-mock": "^29.7.0",
+ "jest-util": "^29.7.0"
},
"dependencies": {
"@jest/types": {
- "version": "29.4.1",
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz",
+ "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
"requires": {
- "@jest/schemas": "^29.4.0",
+ "@jest/schemas": "^29.6.3",
"@types/istanbul-lib-coverage": "^2.0.0",
"@types/istanbul-reports": "^3.0.0",
"@types/node": "*",
@@ -83384,9 +82735,9 @@
}
},
"@types/yargs": {
- "version": "17.0.24",
- "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz",
- "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==",
+ "version": "17.0.31",
+ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.31.tgz",
+ "integrity": "sha512-bocYSx4DI8TmdlvxqGpVNXOgCNR1Jj0gNPhhAY+iz1rgKDAaYrAYdFYnhDV1IFuiuVc9HkOwyDcFxaTElF3/wg==",
"requires": {
"@types/yargs-parser": "*"
}
@@ -83437,11 +82788,12 @@
}
},
"jest-expo": {
- "version": "49.0.0",
- "resolved": "https://registry.npmjs.org/jest-expo/-/jest-expo-49.0.0.tgz",
- "integrity": "sha512-nglYg6QPYSqCsrsOFiGosQi+m1rrqmYluPbFXNnXNEOrB2MvxMOgQJeWfMHDExHMX1ymLWX+7y8mYo6XVJpBJQ==",
+ "version": "50.0.1",
+ "resolved": "https://registry.npmjs.org/jest-expo/-/jest-expo-50.0.1.tgz",
+ "integrity": "sha512-osvA63UDLJ/v7MG9UHjU7WJ0oZ0Krq9UhXxm2s6rdOlnt85ARocyMU57RC0T0yzPN47C9Ref45sEeOIxoV4Mzg==",
"requires": {
- "@expo/config": "~8.1.0",
+ "@expo/config": "~8.5.0",
+ "@expo/json-file": "^8.2.37",
"@jest/create-cache-key-function": "^29.2.1",
"babel-jest": "^29.2.1",
"find-up": "^5.0.0",
@@ -83450,7 +82802,28 @@
"jest-watch-typeahead": "2.2.1",
"json5": "^2.2.3",
"lodash": "^4.17.19",
- "react-test-renderer": "18.2.0"
+ "react-test-renderer": "18.2.0",
+ "stacktrace-js": "^2.0.2"
+ },
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
+ "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
+ "requires": {
+ "@babel/highlight": "^7.10.4"
+ }
+ },
+ "@expo/json-file": {
+ "version": "8.2.37",
+ "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.2.37.tgz",
+ "integrity": "sha512-YaH6rVg11JoTS2P6LsW7ybS2CULjf40AbnAHw2F1eDPuheprNjARZMnyHFPkKv7GuxCy+B9GPcbOKgc4cgA80Q==",
+ "requires": {
+ "@babel/code-frame": "~7.10.4",
+ "json5": "^2.2.2",
+ "write-file-atomic": "^2.3.0"
+ }
+ }
}
},
"jest-get-type": {
@@ -83628,17 +83001,17 @@
}
},
"jest-message-util": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.2.tgz",
- "integrity": "sha512-vnIGYEjoPSuRqV8W9t+Wow95SDp6KPX2Uf7EoeG9G99J2OVh7OSwpS4B6J0NfpEIpfkBNHlBZpA2rblEuEFhZQ==",
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz",
+ "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==",
"requires": {
"@babel/code-frame": "^7.12.13",
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"@types/stack-utils": "^2.0.0",
"chalk": "^4.0.0",
"graceful-fs": "^4.2.9",
"micromatch": "^4.0.4",
- "pretty-format": "^29.6.2",
+ "pretty-format": "^29.7.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.3"
},
@@ -83710,13 +83083,13 @@
}
},
"jest-mock": {
- "version": "29.6.2",
- "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.6.2.tgz",
- "integrity": "sha512-hoSv3lb3byzdKfwqCuT6uTscan471GUECqgNYykg6ob0yiAw3zYc7OrPnI9Qv8Wwoa4lC7AZ9hyS4AiIx5U2zg==",
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz",
+ "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==",
"requires": {
- "@jest/types": "^29.6.1",
+ "@jest/types": "^29.6.3",
"@types/node": "*",
- "jest-util": "^29.6.2"
+ "jest-util": "^29.7.0"
},
"dependencies": {
"@jest/types": {
@@ -84179,9 +83552,9 @@
"requires": {}
},
"jest-util": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz",
- "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==",
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz",
+ "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==",
"requires": {
"@jest/types": "^29.6.3",
"@types/node": "*",
@@ -84615,9 +83988,9 @@
"dev": true
},
"joi": {
- "version": "17.10.2",
- "resolved": "https://registry.npmjs.org/joi/-/joi-17.10.2.tgz",
- "integrity": "sha512-hcVhjBxRNW/is3nNLdGLIjkgXetkeGc2wyhydhz8KumG23Aerk4HPjU5zaPAMRqXQFc0xNqXTC7+zQjxr0GlKA==",
+ "version": "17.11.0",
+ "resolved": "https://registry.npmjs.org/joi/-/joi-17.11.0.tgz",
+ "integrity": "sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==",
"requires": {
"@hapi/hoek": "^9.0.0",
"@hapi/topo": "^5.0.0",
@@ -84730,14 +84103,6 @@
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
},
- "rimraf": {
- "version": "2.6.3",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
- "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
- "requires": {
- "glob": "^7.1.3"
- }
- },
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -84745,14 +84110,6 @@
"requires": {
"has-flag": "^4.0.0"
}
- },
- "temp": {
- "version": "0.8.4",
- "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz",
- "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==",
- "requires": {
- "rimraf": "~2.6.2"
- }
}
}
},
@@ -85101,6 +84458,30 @@
"immediate": "~3.0.5"
}
},
+ "lighthouse-logger": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz",
+ "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==",
+ "requires": {
+ "debug": "^2.6.9",
+ "marky": "^1.2.2"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ }
+ }
+ },
"lightningcss": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.19.0.tgz",
@@ -85498,9 +84879,9 @@
}
},
"lottie-react-native": {
- "version": "6.4.0",
- "resolved": "https://registry.npmjs.org/lottie-react-native/-/lottie-react-native-6.4.0.tgz",
- "integrity": "sha512-wFO/gLPN1KliyznBa8OtYWkc9Vn9OEmIg1/b1536KANFtGaFAeoAGhijVxYKF3UPKJgjJYFmqg0W//FVrSXj+g==",
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/lottie-react-native/-/lottie-react-native-6.4.1.tgz",
+ "integrity": "sha512-DPsUPSxLc3ZffeRQ/AtKtcUl4PzmJEEPt965tNpWSE4vhDkoGFxRe0TPZ45xX8/3HbGsUl48aMdLlAu28MEDsQ==",
"requires": {}
},
"lottie-web": {
@@ -85683,6 +85064,11 @@
"dev": true,
"requires": {}
},
+ "marky": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.5.tgz",
+ "integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q=="
+ },
"matcher": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",
@@ -86423,10 +85809,9 @@
"integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="
},
"metro": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro/-/metro-0.76.8.tgz",
- "integrity": "sha512-oQA3gLzrrYv3qKtuWArMgHPbHu8odZOD9AoavrqSFllkPgOtmkBvNNDLCELqv5SjBfqjISNffypg+5UGG3y0pg==",
- "dev": true,
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro/-/metro-0.80.3.tgz",
+ "integrity": "sha512-7u6HjWVQR7wA/HbxzB0n6iQ0GI9s/fr49N++dZQ41BcrcFxrguIGaRe4W8VI5DtYifCVCjXDIFw6e9+MAccx/Q==",
"requires": {
"@babel/code-frame": "^7.0.0",
"@babel/core": "^7.20.0",
@@ -86436,7 +85821,6 @@
"@babel/traverse": "^7.20.0",
"@babel/types": "^7.20.0",
"accepts": "^1.3.7",
- "async": "^3.2.2",
"chalk": "^4.0.0",
"ci-info": "^2.0.0",
"connect": "^3.6.5",
@@ -86444,28 +85828,25 @@
"denodeify": "^1.2.1",
"error-stack-parser": "^2.0.6",
"graceful-fs": "^4.2.4",
- "hermes-parser": "0.12.0",
+ "hermes-parser": "0.18.2",
"image-size": "^1.0.2",
"invariant": "^2.2.4",
- "jest-worker": "^27.2.0",
+ "jest-worker": "^29.6.3",
"jsc-safe-url": "^0.2.2",
"lodash.throttle": "^4.1.1",
- "metro-babel-transformer": "0.76.8",
- "metro-cache": "0.76.8",
- "metro-cache-key": "0.76.8",
- "metro-config": "0.76.8",
- "metro-core": "0.76.8",
- "metro-file-map": "0.76.8",
- "metro-inspector-proxy": "0.76.8",
- "metro-minify-terser": "0.76.8",
- "metro-minify-uglify": "0.76.8",
- "metro-react-native-babel-preset": "0.76.8",
- "metro-resolver": "0.76.8",
- "metro-runtime": "0.76.8",
- "metro-source-map": "0.76.8",
- "metro-symbolicate": "0.76.8",
- "metro-transform-plugins": "0.76.8",
- "metro-transform-worker": "0.76.8",
+ "metro-babel-transformer": "0.80.3",
+ "metro-cache": "0.80.3",
+ "metro-cache-key": "0.80.3",
+ "metro-config": "0.80.3",
+ "metro-core": "0.80.3",
+ "metro-file-map": "0.80.3",
+ "metro-minify-terser": "0.80.3",
+ "metro-resolver": "0.80.3",
+ "metro-runtime": "0.80.3",
+ "metro-source-map": "0.80.3",
+ "metro-symbolicate": "0.80.3",
+ "metro-transform-plugins": "0.80.3",
+ "metro-transform-worker": "0.80.3",
"mime-types": "^2.1.27",
"node-fetch": "^2.2.0",
"nullthrows": "^1.1.1",
@@ -86482,7 +85863,6 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
"requires": {
"color-convert": "^2.0.1"
}
@@ -86491,7 +85871,6 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -86500,14 +85879,12 @@
"ci-info": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
- "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
- "dev": true
+ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="
},
"cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
- "dev": true,
"requires": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
@@ -86518,7 +85895,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
"requires": {
"color-name": "~1.1.4"
}
@@ -86526,14 +85902,12 @@
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
"requires": {
"ms": "2.0.0"
}
@@ -86541,16 +85915,28 @@
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
+ },
+ "hermes-estree": {
+ "version": "0.18.2",
+ "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.18.2.tgz",
+ "integrity": "sha512-KoLsoWXJ5o81nit1wSyEZnWUGy9cBna9iYMZBR7skKh7okYAYKqQ9/OczwpMHn/cH0hKDyblulGsJ7FknlfVxQ=="
+ },
+ "hermes-parser": {
+ "version": "0.18.2",
+ "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.18.2.tgz",
+ "integrity": "sha512-1eQfvib+VPpgBZ2zYKQhpuOjw1tH+Emuib6QmjkJWJMhyjM8xnXMvA+76o9LhF0zOAJDZgPfQhg43cyXEyl5Ew==",
+ "requires": {
+ "hermes-estree": "0.18.2"
+ }
},
"jest-worker": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
- "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
- "dev": true,
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz",
+ "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==",
"requires": {
"@types/node": "*",
+ "jest-util": "^29.7.0",
"merge-stream": "^2.0.0",
"supports-color": "^8.0.0"
},
@@ -86559,7 +85945,6 @@
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
- "dev": true,
"requires": {
"has-flag": "^4.0.0"
}
@@ -86569,26 +85954,22 @@
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
- "dev": true
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"serialize-error": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz",
- "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==",
- "dev": true
+ "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw=="
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
- "dev": true
+ "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
"requires": {
"has-flag": "^4.0.0"
}
@@ -86597,20 +85978,17 @@
"version": "7.5.9",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
- "dev": true,
"requires": {}
},
"y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
- "dev": true
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
},
"yargs": {
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
- "dev": true,
"requires": {
"cliui": "^8.0.1",
"escalade": "^3.1.1",
@@ -86624,58 +86002,67 @@
"yargs-parser": {
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
- "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
- "dev": true
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="
}
}
},
"metro-babel-transformer": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.76.8.tgz",
- "integrity": "sha512-Hh6PW34Ug/nShlBGxkwQJSgPGAzSJ9FwQXhUImkzdsDgVu6zj5bx258J8cJVSandjNoQ8nbaHK6CaHlnbZKbyA==",
- "dev": true,
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.80.3.tgz",
+ "integrity": "sha512-Si1GO9fhiLi3DfHseFDaZcU+Y6iYHx54rszILnBIx80aas3pRZpL3z/UsEZ7coTQZTFsblt2QDIE+Izxlq4mwQ==",
"requires": {
"@babel/core": "^7.20.0",
- "hermes-parser": "0.12.0",
+ "hermes-parser": "0.18.2",
"nullthrows": "^1.1.1"
+ },
+ "dependencies": {
+ "hermes-estree": {
+ "version": "0.18.2",
+ "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.18.2.tgz",
+ "integrity": "sha512-KoLsoWXJ5o81nit1wSyEZnWUGy9cBna9iYMZBR7skKh7okYAYKqQ9/OczwpMHn/cH0hKDyblulGsJ7FknlfVxQ=="
+ },
+ "hermes-parser": {
+ "version": "0.18.2",
+ "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.18.2.tgz",
+ "integrity": "sha512-1eQfvib+VPpgBZ2zYKQhpuOjw1tH+Emuib6QmjkJWJMhyjM8xnXMvA+76o9LhF0zOAJDZgPfQhg43cyXEyl5Ew==",
+ "requires": {
+ "hermes-estree": "0.18.2"
+ }
+ }
}
},
"metro-cache": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.76.8.tgz",
- "integrity": "sha512-QBJSJIVNH7Hc/Yo6br/U/qQDUpiUdRgZ2ZBJmvAbmAKp2XDzsapnMwK/3BGj8JNWJF7OLrqrYHsRsukSbUBpvQ==",
- "dev": true,
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.80.3.tgz",
+ "integrity": "sha512-7gHcOIXdAHCBzsovF4b+VgcfIZtCpCIFiT2zx9amU58xrmkx+PRIl1KZDIUfRBbGrO9HJtZxH7lr7/hoiLIUWA==",
"requires": {
- "metro-core": "0.76.8",
+ "metro-core": "0.80.3",
"rimraf": "^3.0.2"
}
},
"metro-cache-key": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.76.8.tgz",
- "integrity": "sha512-buKQ5xentPig9G6T37Ww/R/bC+/V1MA5xU/D8zjnhlelsrPG6w6LtHUS61ID3zZcMZqYaELWk5UIadIdDsaaLw==",
- "dev": true
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.80.3.tgz",
+ "integrity": "sha512-WNrtDpbhtW2Yqjp1t0WxJhKNR/Zbo1LZ4WvHsdv/PraAs2mr+SaM5bbiptBSKOOGJkV/FIQveW5riZi53JnCbw=="
},
"metro-config": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.76.8.tgz",
- "integrity": "sha512-SL1lfKB0qGHALcAk2zBqVgQZpazDYvYFGwCK1ikz0S6Y/CM2i2/HwuZN31kpX6z3mqjv/6KvlzaKoTb1otuSAA==",
- "dev": true,
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.80.3.tgz",
+ "integrity": "sha512-cE7KPT1Usdrd2nLEVpzukKWmeBU1PufHPkuD9BjjtoABbzdj35gMLDnK+mhjSq9km2vF2QEPtE0M+WKvq9pXfQ==",
"requires": {
"connect": "^3.6.5",
"cosmiconfig": "^5.0.5",
- "jest-validate": "^29.2.1",
- "metro": "0.76.8",
- "metro-cache": "0.76.8",
- "metro-core": "0.76.8",
- "metro-runtime": "0.76.8"
+ "jest-validate": "^29.6.3",
+ "metro": "0.80.3",
+ "metro-cache": "0.80.3",
+ "metro-core": "0.80.3",
+ "metro-runtime": "0.80.3"
},
"dependencies": {
"cosmiconfig": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
"integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
- "dev": true,
"requires": {
"import-fresh": "^2.0.0",
"is-directory": "^0.3.1",
@@ -86687,7 +86074,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
"integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==",
- "dev": true,
"requires": {
"caller-path": "^2.0.0",
"resolve-from": "^3.0.0"
@@ -86697,7 +86083,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
"integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
- "dev": true,
"requires": {
"error-ex": "^1.3.1",
"json-parse-better-errors": "^1.0.1"
@@ -86706,26 +86091,23 @@
"resolve-from": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
- "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==",
- "dev": true
+ "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw=="
}
}
},
"metro-core": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.76.8.tgz",
- "integrity": "sha512-sl2QLFI3d1b1XUUGxwzw/KbaXXU/bvFYrSKz6Sg19AdYGWFyzsgZ1VISRIDf+HWm4R/TJXluhWMEkEtZuqi3qA==",
- "dev": true,
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.80.3.tgz",
+ "integrity": "sha512-X2ZfAvR55TdD/Rv9i4gYVI68JpRPHcpKpkr6IVtidFPoNjf4Fodh1qH7gEAJUnO5FL3a1JyPffbW6eFaXPxkFw==",
"requires": {
"lodash.throttle": "^4.1.1",
- "metro-resolver": "0.76.8"
+ "metro-resolver": "0.80.3"
}
},
"metro-file-map": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.76.8.tgz",
- "integrity": "sha512-A/xP1YNEVwO1SUV9/YYo6/Y1MmzhL4ZnVgcJC3VmHp/BYVOXVStzgVbWv2wILe56IIMkfXU+jpXrGKKYhFyHVw==",
- "dev": true,
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.80.3.tgz",
+ "integrity": "sha512-4qu1ABPZRvboGGB8Q2RlQ26kZRWRCMDiktgCCrX/57V6cnWgdbdTrpnsgmU3i0Q7iiw+FevOGlfD4HqdauQ59g==",
"requires": {
"anymatch": "^3.0.3",
"debug": "^2.2.0",
@@ -86733,76 +86115,17 @@
"fsevents": "^2.3.2",
"graceful-fs": "^4.2.4",
"invariant": "^2.2.4",
- "jest-regex-util": "^27.0.6",
- "jest-util": "^27.2.0",
- "jest-worker": "^27.2.0",
+ "jest-worker": "^29.6.3",
"micromatch": "^4.0.4",
"node-abort-controller": "^3.1.1",
"nullthrows": "^1.1.1",
"walker": "^1.0.7"
},
"dependencies": {
- "@jest/types": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz",
- "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==",
- "dev": true,
- "requires": {
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^16.0.0",
- "chalk": "^4.0.0"
- }
- },
- "@types/yargs": {
- "version": "16.0.6",
- "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.6.tgz",
- "integrity": "sha512-oTP7/Q13GSPrgcwEwdlnkoZSQ1Hg9THe644qq8PG6hhJzjZ3qj1JjEFPIwWV/IXVs5XGIVqtkNOS9kh63WIJ+A==",
- "dev": true,
- "requires": {
- "@types/yargs-parser": "*"
- }
- },
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
"requires": {
"ms": "2.0.0"
}
@@ -86810,165 +86133,48 @@
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "jest-regex-util": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz",
- "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==",
- "dev": true
- },
- "jest-util": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz",
- "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==",
- "dev": true,
- "requires": {
- "@jest/types": "^27.5.1",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "ci-info": "^3.2.0",
- "graceful-fs": "^4.2.9",
- "picomatch": "^2.2.3"
- }
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
},
"jest-worker": {
- "version": "27.5.1",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
- "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
- "dev": true,
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz",
+ "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==",
"requires": {
"@types/node": "*",
+ "jest-util": "^29.7.0",
"merge-stream": "^2.0.0",
"supports-color": "^8.0.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "8.1.1",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
- "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
- "dev": true
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
- "metro-inspector-proxy": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.76.8.tgz",
- "integrity": "sha512-Us5o5UEd4Smgn1+TfHX4LvVPoWVo9VsVMn4Ldbk0g5CQx3Gu0ygc/ei2AKPGTwsOZmKxJeACj7yMH2kgxQP/iw==",
- "dev": true,
- "requires": {
- "connect": "^3.6.5",
- "debug": "^2.2.0",
- "node-fetch": "^2.2.0",
- "ws": "^7.5.1",
- "yargs": "^17.6.2"
- },
- "dependencies": {
- "cliui": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
- "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
- "dev": true,
- "requires": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.1",
- "wrap-ansi": "^7.0.0"
- }
- },
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
- "requires": {
- "ms": "2.0.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
- "dev": true
- },
- "ws": {
- "version": "7.5.9",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
- "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
- "dev": true,
- "requires": {}
- },
- "y18n": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
- "dev": true
- },
- "yargs": {
- "version": "17.7.2",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
- "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
- "dev": true,
- "requires": {
- "cliui": "^8.0.1",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "require-directory": "^2.1.1",
- "string-width": "^4.2.3",
- "y18n": "^5.0.5",
- "yargs-parser": "^21.1.1"
- }
- },
- "yargs-parser": {
- "version": "21.1.1",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
- "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
- "dev": true
- }
- }
- },
"metro-minify-terser": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.76.8.tgz",
- "integrity": "sha512-Orbvg18qXHCrSj1KbaeSDVYRy/gkro2PC7Fy2tDSH1c9RB4aH8tuMOIXnKJE+1SXxBtjWmQ5Yirwkth2DyyEZA==",
- "dev": true,
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.80.3.tgz",
+ "integrity": "sha512-gVFwoL86emFoYbI2DZKk1Ved2CklYv//huWriF0UpLJHmVEO9ii2ajTx3aIxgSeuxFLPJhdp8RgUB2EDCooaJw==",
"requires": {
"terser": "^5.15.0"
}
},
- "metro-minify-uglify": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.76.8.tgz",
- "integrity": "sha512-6l8/bEvtVaTSuhG1FqS0+Mc8lZ3Bl4RI8SeRIifVLC21eeSDp4CEBUWSGjpFyUDfi6R5dXzYaFnSgMNyfxADiQ==",
- "dev": true,
- "requires": {
- "uglify-es": "^3.1.9"
- }
- },
"metro-react-native-babel-preset": {
"version": "0.76.8",
"resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.76.8.tgz",
"integrity": "sha512-Ptza08GgqzxEdK8apYsjTx2S8WDUlS2ilBlu9DR1CUcHmg4g3kOkFylZroogVAUKtpYQNYwAvdsjmrSdDNtiAg==",
+ "dev": true,
+ "peer": true,
"requires": {
"@babel/core": "^7.20.0",
"@babel/plugin-proposal-async-generator-functions": "^7.0.0",
@@ -87012,56 +86218,36 @@
},
"dependencies": {
"react-refresh": {
- "version": "0.4.3"
+ "version": "0.4.3",
+ "dev": true,
+ "peer": true
}
}
},
- "metro-react-native-babel-transformer": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.76.8.tgz",
- "integrity": "sha512-3h+LfS1WG1PAzhq8QF0kfXjxuXetbY/lgz8vYMQhgrMMp17WM1DNJD0gjx8tOGYbpbBC1qesJ45KMS4o5TA73A==",
- "dev": true,
- "requires": {
- "@babel/core": "^7.20.0",
- "babel-preset-fbjs": "^3.4.0",
- "hermes-parser": "0.12.0",
- "metro-react-native-babel-preset": "0.76.8",
- "nullthrows": "^1.1.1"
- }
- },
"metro-resolver": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.76.8.tgz",
- "integrity": "sha512-KccOqc10vrzS7ZhG2NSnL2dh3uVydarB7nOhjreQ7C4zyWuiW9XpLC4h47KtGQv3Rnv/NDLJYeDqaJ4/+140HQ==",
- "dev": true
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.80.3.tgz",
+ "integrity": "sha512-zwa0i32rj/TI3NivcvMXHJwTG2gUgo2dXdcnAJlhEKKQvyN+7AfhNdQSlDdDqMQmU7FaLRdeWORnQJbYCrprQQ=="
},
"metro-runtime": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.76.8.tgz",
- "integrity": "sha512-XKahvB+iuYJSCr3QqCpROli4B4zASAYpkK+j3a0CJmokxCDNbgyI4Fp88uIL6rNaZfN0Mv35S0b99SdFXIfHjg==",
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.80.3.tgz",
+ "integrity": "sha512-16RKcwpxriNnPdE5eKWJu7/KLgxE+AaDAdYthoS6zbzjaOu7RiY2zPM1Elz175Rw//74kOwtKXgxTW8ADHB8SQ==",
"requires": {
- "@babel/runtime": "^7.0.0",
- "react-refresh": "^0.4.0"
- },
- "dependencies": {
- "react-refresh": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz",
- "integrity": "sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA=="
- }
+ "@babel/runtime": "^7.0.0"
}
},
"metro-source-map": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.76.8.tgz",
- "integrity": "sha512-Hh0ncPsHPVf6wXQSqJqB3K9Zbudht4aUtNpNXYXSxH+pteWqGAXnjtPsRAnCsCWl38wL0jYF0rJDdMajUI3BDw==",
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.80.3.tgz",
+ "integrity": "sha512-5DYcOLPjDLx84ZCZ1i0DuWSPU7AY5G/7tR+u/WN6CZNxLyYEe3TwUBdIUgQj4HgZJl/zZ/7bGYJQOHd7ubuO0w==",
"requires": {
"@babel/traverse": "^7.20.0",
"@babel/types": "^7.20.0",
"invariant": "^2.2.4",
- "metro-symbolicate": "0.76.8",
+ "metro-symbolicate": "0.80.3",
"nullthrows": "^1.1.1",
- "ob1": "0.76.8",
+ "ob1": "0.80.3",
"source-map": "^0.5.6",
"vlq": "^1.0.0"
},
@@ -87074,12 +86260,12 @@
}
},
"metro-symbolicate": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.76.8.tgz",
- "integrity": "sha512-LrRL3uy2VkzrIXVlxoPtqb40J6Bf1mlPNmUQewipc3qfKKFgtPHBackqDy1YL0njDsWopCKcfGtFYLn0PTUn3w==",
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.80.3.tgz",
+ "integrity": "sha512-baIt8Ss2vTGbxolRTa5yg+tKVAIAB1OpwMzJ0FSUjLs+HDAzaOtSpGbNd3DPc+pzX8Gj/rdbDOA0wPuOhVsHKQ==",
"requires": {
"invariant": "^2.2.4",
- "metro-source-map": "0.76.8",
+ "metro-source-map": "0.80.3",
"nullthrows": "^1.1.1",
"source-map": "^0.5.6",
"through2": "^2.0.1",
@@ -87094,10 +86280,9 @@
}
},
"metro-transform-plugins": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.76.8.tgz",
- "integrity": "sha512-PlkGTQNqS51Bx4vuufSQCdSn2R2rt7korzngo+b5GCkeX5pjinPjnO2kNhQ8l+5bO0iUD/WZ9nsM2PGGKIkWFA==",
- "dev": true,
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.80.3.tgz",
+ "integrity": "sha512-/2hGGRdJPrNfB9lz8unukaqQpGpDhYwNM0Odfh37OVFjygMB30Ffd8neQ4FNqnHnFxhl5j8VTcopUg6QhygMGQ==",
"requires": {
"@babel/core": "^7.20.0",
"@babel/generator": "^7.20.0",
@@ -87107,22 +86292,20 @@
}
},
"metro-transform-worker": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.76.8.tgz",
- "integrity": "sha512-mE1fxVAnJKmwwJyDtThildxxos9+DGs9+vTrx2ktSFMEVTtXS/bIv2W6hux1pqivqAfyJpTeACXHk5u2DgGvIQ==",
- "dev": true,
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.80.3.tgz",
+ "integrity": "sha512-10ZwMDuSWyHwqNnZ50baNtHNuHhOnqThbTOgv03PsrmPHWmSv4/rrmm7711tEyLUxptY3A1hEgJ+LKYyOIQiUA==",
"requires": {
"@babel/core": "^7.20.0",
"@babel/generator": "^7.20.0",
"@babel/parser": "^7.20.0",
"@babel/types": "^7.20.0",
- "babel-preset-fbjs": "^3.4.0",
- "metro": "0.76.8",
- "metro-babel-transformer": "0.76.8",
- "metro-cache": "0.76.8",
- "metro-cache-key": "0.76.8",
- "metro-source-map": "0.76.8",
- "metro-transform-plugins": "0.76.8",
+ "metro": "0.80.3",
+ "metro-babel-transformer": "0.80.3",
+ "metro-cache": "0.80.3",
+ "metro-cache-key": "0.80.3",
+ "metro-source-map": "0.80.3",
+ "metro-transform-plugins": "0.80.3",
"nullthrows": "^1.1.1"
}
},
@@ -87925,8 +87108,7 @@
"mrmime": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz",
- "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==",
- "dev": true
+ "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw=="
},
"ms": {
"version": "2.1.2",
@@ -88015,9 +87197,9 @@
"optional": true
},
"nanoid": {
- "version": "3.3.6",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
- "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA=="
+ "version": "3.3.7",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
+ "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g=="
},
"nanomatch": {
"version": "1.2.13",
@@ -88329,9 +87511,9 @@
"version": "2.2.2"
},
"ob1": {
- "version": "0.76.8",
- "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.76.8.tgz",
- "integrity": "sha512-dlBkJJV5M/msj9KYA9upc+nUWVwuOFFTbu28X6kZeGwcuW+JxaHSBZ70SYQnk5M+j5JbNLR6yKHmgW4M5E7X5g=="
+ "version": "0.80.3",
+ "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.80.3.tgz",
+ "integrity": "sha512-lKJ/Wp6eSyYKYKYds1lgiDRtD2j9nNhrhx4hwegxYXTBkWz4dqermZV+Bq0iw0SszUIb+fC+btNSXwc4AG1lBQ=="
},
"object-assign": {
"version": "4.1.1",
@@ -89129,7 +88311,6 @@
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz",
"integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==",
- "dev": true,
"requires": {
"lru-cache": "^9.1.1 || ^10.0.0",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
@@ -89138,14 +88319,12 @@
"lru-cache": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz",
- "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==",
- "dev": true
+ "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g=="
},
"minipass": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz",
- "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==",
- "dev": true
+ "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg=="
}
}
},
@@ -89270,18 +88449,21 @@
},
"pkg-up": {
"version": "3.1.0",
+ "dev": true,
"requires": {
"find-up": "^3.0.0"
},
"dependencies": {
"find-up": {
"version": "3.0.0",
+ "dev": true,
"requires": {
"locate-path": "^3.0.0"
}
},
"locate-path": {
"version": "3.0.0",
+ "dev": true,
"requires": {
"p-locate": "^3.0.0",
"path-exists": "^3.0.0"
@@ -89289,12 +88471,14 @@
},
"p-limit": {
"version": "2.3.0",
+ "dev": true,
"requires": {
"p-try": "^2.0.0"
}
},
"p-locate": {
"version": "3.0.0",
+ "dev": true,
"requires": {
"p-limit": "^2.0.0"
}
@@ -89525,9 +88709,9 @@
}
},
"pretty-format": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz",
- "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==",
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
+ "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
"requires": {
"@jest/schemas": "^29.6.3",
"ansi-styles": "^5.0.0",
@@ -90165,43 +89349,44 @@
}
},
"react-native": {
- "version": "0.72.4",
- "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.72.4.tgz",
- "integrity": "sha512-+vrObi0wZR+NeqL09KihAAdVlQ9IdplwznJWtYrjnQ4UbCW6rkzZJebRsugwUneSOKNFaHFEo1uKU89HsgtYBg==",
- "requires": {
- "@jest/create-cache-key-function": "^29.2.1",
- "@react-native-community/cli": "11.3.6",
- "@react-native-community/cli-platform-android": "11.3.6",
- "@react-native-community/cli-platform-ios": "11.3.6",
- "@react-native/assets-registry": "^0.72.0",
- "@react-native/codegen": "^0.72.6",
- "@react-native/gradle-plugin": "^0.72.11",
- "@react-native/js-polyfills": "^0.72.1",
- "@react-native/normalize-colors": "^0.72.0",
- "@react-native/virtualized-lists": "^0.72.8",
+ "version": "0.73.2",
+ "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.73.2.tgz",
+ "integrity": "sha512-7zj9tcUYpJUBdOdXY6cM8RcXYWkyql4kMyGZflW99E5EuFPoC7Ti+ZQSl7LP9ZPzGD0vMfslwyDW0I4tPWUCFw==",
+ "requires": {
+ "@jest/create-cache-key-function": "^29.6.3",
+ "@react-native-community/cli": "12.3.0",
+ "@react-native-community/cli-platform-android": "12.3.0",
+ "@react-native-community/cli-platform-ios": "12.3.0",
+ "@react-native/assets-registry": "0.73.1",
+ "@react-native/codegen": "0.73.2",
+ "@react-native/community-cli-plugin": "0.73.12",
+ "@react-native/gradle-plugin": "0.73.4",
+ "@react-native/js-polyfills": "0.73.1",
+ "@react-native/normalize-colors": "0.73.2",
+ "@react-native/virtualized-lists": "0.73.4",
"abort-controller": "^3.0.0",
"anser": "^1.4.9",
- "base64-js": "^1.1.2",
- "deprecated-react-native-prop-types": "4.1.0",
+ "ansi-regex": "^5.0.0",
+ "base64-js": "^1.5.1",
+ "deprecated-react-native-prop-types": "^5.0.0",
"event-target-shim": "^5.0.1",
- "flow-enums-runtime": "^0.0.5",
+ "flow-enums-runtime": "^0.0.6",
"invariant": "^2.2.4",
- "jest-environment-node": "^29.2.1",
+ "jest-environment-node": "^29.6.3",
"jsc-android": "^250231.0.0",
"memoize-one": "^5.0.0",
- "metro-runtime": "0.76.8",
- "metro-source-map": "0.76.8",
+ "metro-runtime": "^0.80.3",
+ "metro-source-map": "^0.80.3",
"mkdirp": "^0.5.1",
"nullthrows": "^1.1.1",
"pretty-format": "^26.5.2",
"promise": "^8.3.0",
- "react-devtools-core": "^4.27.2",
- "react-refresh": "^0.4.0",
+ "react-devtools-core": "^4.27.7",
+ "react-refresh": "^0.14.0",
"react-shallow-renderer": "^16.15.0",
"regenerator-runtime": "^0.13.2",
"scheduler": "0.24.0-canary-efb381bbf-20230505",
"stacktrace-parser": "^0.1.10",
- "use-sync-external-store": "^1.0.0",
"whatwg-fetch": "^3.0.0",
"ws": "^6.2.2",
"yargs": "^17.6.2"
@@ -90244,13 +89429,13 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"deprecated-react-native-prop-types": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-4.1.0.tgz",
- "integrity": "sha512-WfepZHmRbbdTvhcolb8aOKEvQdcmTMn5tKLbqbXmkBvjFjRVWAYqsXk/DBsV8TZxws8SdGHLuHaJrHSQUPRdfw==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-5.0.0.tgz",
+ "integrity": "sha512-cIK8KYiiGVOFsKdPMmm1L3tA/Gl+JopXL6F5+C7x39MyPsQYnP57Im/D6bNUzcborD7fcMwiwZqcBdBXXZucYQ==",
"requires": {
- "@react-native/normalize-colors": "*",
- "invariant": "*",
- "prop-types": "*"
+ "@react-native/normalize-colors": "^0.73.0",
+ "invariant": "^2.2.4",
+ "prop-types": "^15.8.1"
}
},
"mkdirp": {
@@ -90286,9 +89471,9 @@
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
},
"react-refresh": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz",
- "integrity": "sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA=="
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
+ "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ=="
},
"scheduler": {
"version": "0.24.0-canary-efb381bbf-20230505",
@@ -90413,9 +89598,11 @@
}
},
"react-native-flipper": {
- "version": "https://gitpkg.now.sh/facebook/flipper/react-native/react-native-flipper?9cacc9b59402550eae866e0e81e5f0c2f8203e6b",
+ "version": "0.159.0",
+ "resolved": "https://gitpkg.now.sh/facebook/flipper/react-native/react-native-flipper?9cacc9b59402550eae866e0e81e5f0c2f8203e6b",
"integrity": "sha512-M784S/qPuN/HqjdvXg98HIDmfm0sF8mACc56YNg87nzEF90zKSKp0XyOE83SEW+UJX2Gq/rf9BvM2GZeXlrhnQ==",
"dev": true,
+ "peer": true,
"requires": {}
},
"react-native-fs": {
@@ -90428,9 +89615,9 @@
}
},
"react-native-gesture-handler": {
- "version": "2.12.0",
- "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.12.0.tgz",
- "integrity": "sha512-rr+XwVzXAVpY8co25ukvyI38fKCxTQjz7WajeZktl8qUPdh1twnSExgpT47DqDi4n+m+OiJPAnHfZOkqqAQMOg==",
+ "version": "2.14.0",
+ "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.14.0.tgz",
+ "integrity": "sha512-cOmdaqbpzjWrOLUpX3hdSjsMby5wq3PIEdMq7okJeg9DmCzanysHSrktw1cXWNc/B5MAgxAn9J7Km0/4UIqKAQ==",
"requires": {
"@egjs/hammerjs": "^2.0.17",
"hoist-non-react-statics": "^3.3.0",
@@ -90515,9 +89702,9 @@
}
},
"react-native-onyx": {
- "version": "1.0.118",
- "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.118.tgz",
- "integrity": "sha512-w54jO+Bpu1ElHsrxZXIIpcBqNkrUvuVCQmwWdfOW5LvO4UwsPSwmMxzExbUZ4ip+7CROmm10IgXFaAoyfeYSVQ==",
+ "version": "1.0.126",
+ "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.126.tgz",
+ "integrity": "sha512-tUJI1mQaWXLfyBFYQQWM6mm9GiCqIXGvjbqJkH1fLY3OqbGW6DyH4CxC+qJrqfi4bKZgZHp5xlBHhkPV4pKK2A==",
"requires": {
"ascii-table": "0.0.9",
"fast-equals": "^4.0.3",
@@ -90525,15 +89712,15 @@
}
},
"react-native-pager-view": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.2.0.tgz",
- "integrity": "sha512-pf9OnL/Tkr+5s4Gjmsn7xh91PtJLDa6qxYa/bmtUhd/+s4cQdWQ8DIFoOFghwZIHHHwVdWtoXkp6HtpjN+r20g==",
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.2.2.tgz",
+ "integrity": "sha512-MLkJB7iP6v0Hd4/B4/R/gLCSE+YBtjxG/vHZYBDU+fI3U7HBYgKAg4o6ad8HxbKVcWWyRDNeeVRGISw1MUjlHw==",
"requires": {}
},
"react-native-pdf": {
- "version": "6.7.3",
- "resolved": "https://registry.npmjs.org/react-native-pdf/-/react-native-pdf-6.7.3.tgz",
- "integrity": "sha512-bK1fVkj18kBA5YlRFNJ3/vJ1bEX3FDHyAPY6ArtIdVs+vv0HzcK5WH9LSd2bxUsEMIyY9CSjP4j8BcxNXTiQkQ==",
+ "version": "6.7.4",
+ "resolved": "https://registry.npmjs.org/react-native-pdf/-/react-native-pdf-6.7.4.tgz",
+ "integrity": "sha512-sBeNcsrTRnLjmiU9Wx7Uk0K2kPSQtKIIG+FECdrEG16TOdtmQ3iqqEwt0dmy0pJegpg07uES5BXqiKsKkRUIFw==",
"requires": {
"crypto-js": "4.2.0",
"deprecated-react-native-prop-types": "^2.3.0"
@@ -90644,24 +89831,24 @@
}
},
"react-native-safe-area-context": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.4.1.tgz",
- "integrity": "sha512-N9XTjiuD73ZpVlejHrUWIFZc+6Z14co1K/p1IFMkImU7+avD69F3y+lhkqA2hN/+vljdZrBSiOwXPkuo43nFQA==",
+ "version": "4.7.4",
+ "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.7.4.tgz",
+ "integrity": "sha512-3LR3DCq9pdzlbq6vsHGWBFehXAKDh2Ljug6jWhLWs1QFuJHM6AS2+mH2JfKlB2LqiSFZOBcZfHQFz0sGaA3uqg==",
"requires": {}
},
"react-native-screens": {
- "version": "3.21.0",
- "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.21.0.tgz",
- "integrity": "sha512-SybzBhceTN2LUfzvEQxpZ9SchlFgEdsR/+YOKcpIhKg2BdRObdIyQsRoJBvduZ55lKbO9Gpyl3Ke8tngz3873g==",
+ "version": "3.29.0",
+ "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.29.0.tgz",
+ "integrity": "sha512-yB1GoAMamFAcYf4ku94uBPn0/ani9QG7NdI98beJ5cet2YFESYYzuEIuU+kt+CNRcO8qqKeugxlfgAa3HyTqlg==",
"requires": {
"react-freeze": "^1.0.0",
"warn-once": "^0.1.0"
}
},
"react-native-svg": {
- "version": "13.14.0",
- "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-13.14.0.tgz",
- "integrity": "sha512-27ZnxUkHgWICimhuj6MuqBkISN53lVvgWJB7pIypjXysAyM+nqgQBPh4vXg+7MbqLBoYvR4PiBgKfwwGAqVxHg==",
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-14.0.0.tgz",
+ "integrity": "sha512-17W/gWXRUMS7p7PSHu/WyGkZUc1NzRTGxxXc0VqBLjzKSchyb0EmgsiWf9aKmfC6gmY0wcsmKZcGV41bCcNfBA==",
"requires": {
"css-select": "^5.1.0",
"css-tree": "^1.1.3"
@@ -90684,8 +89871,12 @@
}
},
"react-native-view-shot": {
- "version": "3.6.0",
- "requires": {}
+ "version": "3.8.0",
+ "resolved": "https://registry.npmjs.org/react-native-view-shot/-/react-native-view-shot-3.8.0.tgz",
+ "integrity": "sha512-4cU8SOhMn3YQIrskh+5Q8VvVRxQOu8/s1M9NAL4z5BY1Rm0HXMWkQJ4N0XsZ42+Yca+y86ISF3LC5qdLPvPuiA==",
+ "requires": {
+ "html2canvas": "^1.4.1"
+ }
},
"react-native-vision-camera": {
"version": "2.16.2",
@@ -90722,7 +89913,9 @@
"requires": {}
},
"react-native-webview": {
- "version": "11.23.0",
+ "version": "13.6.3",
+ "resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-13.6.3.tgz",
+ "integrity": "sha512-IApO0JSj0uAWsBGKWagyfgDYoX29piiMYLmkHtRjKeL1rIVjLoR/bMe7KJ/0X47y86b//a6u3cYQtphyay+F2A==",
"requires": {
"escape-string-regexp": "2.0.0",
"invariant": "2.2.4"
@@ -92028,7 +91221,8 @@
"version": "1.0.0"
},
"reselect": {
- "version": "4.1.7"
+ "version": "4.1.7",
+ "dev": true
},
"resolve": {
"version": "1.22.4",
@@ -92079,7 +91273,9 @@
"devOptional": true
},
"resolve.exports": {
- "version": "2.0.0"
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz",
+ "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg=="
},
"responselike": {
"version": "2.0.1",
@@ -92557,6 +91753,11 @@
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
},
+ "set-cookie-parser": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz",
+ "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ=="
+ },
"set-value": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
@@ -93455,6 +92656,11 @@
"integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==",
"dev": true
},
+ "stream-slice": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/stream-slice/-/stream-slice-0.1.2.tgz",
+ "integrity": "sha512-QzQxpoacatkreL6jsxnVb7X5R/pGw9OUv2qWTYWnmLpg4NdN31snPy/f3TdQE1ZUXaThRvj1Zw4/OGg0ZkaLMA=="
+ },
"strict-uri-encode": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
@@ -93491,7 +92697,6 @@
"version": "npm:string-width@4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@@ -93533,13 +92738,15 @@
}
},
"string.prototype.replaceall": {
- "version": "1.0.6",
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/string.prototype.replaceall/-/string.prototype.replaceall-1.0.8.tgz",
+ "integrity": "sha512-MmCXb9980obcnmbEd3guqVl6lXTxpP28zASfgAlAhlBMw5XehQeSKsdIWlAYtLxp/1GtALwex+2HyoIQtaLQwQ==",
"requires": {
"call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1",
- "get-intrinsic": "^1.1.1",
- "has-symbols": "^1.0.2",
+ "define-properties": "^1.2.0",
+ "es-abstract": "^1.22.1",
+ "get-intrinsic": "^1.2.1",
+ "has-symbols": "^1.0.3",
"is-regex": "^1.1.4"
}
},
@@ -93602,7 +92809,6 @@
"version": "npm:strip-ansi@6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
"requires": {
"ansi-regex": "^5.0.1"
},
@@ -93610,8 +92816,7 @@
"ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
}
}
},
@@ -93679,13 +92884,13 @@
"integrity": "sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA=="
},
"sucrase": {
- "version": "3.34.0",
- "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz",
- "integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==",
+ "version": "3.35.0",
+ "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
+ "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
"requires": {
"@jridgewell/gen-mapping": "^0.3.2",
"commander": "^4.0.0",
- "glob": "7.1.6",
+ "glob": "^10.3.10",
"lines-and-columns": "^1.1.6",
"mz": "^2.7.0",
"pirates": "^4.0.1",
@@ -93702,10 +92907,57 @@
"@jridgewell/trace-mapping": "^0.3.9"
}
},
+ "brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "requires": {
+ "balanced-match": "^1.0.0"
+ }
+ },
"commander": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
"integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="
+ },
+ "foreground-child": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
+ "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==",
+ "requires": {
+ "cross-spawn": "^7.0.0",
+ "signal-exit": "^4.0.1"
+ }
+ },
+ "glob": {
+ "version": "10.3.10",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
+ "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==",
+ "requires": {
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^2.3.5",
+ "minimatch": "^9.0.1",
+ "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0",
+ "path-scurry": "^1.10.1"
+ }
+ },
+ "minimatch": {
+ "version": "9.0.3",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+ "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+ "requires": {
+ "brace-expansion": "^2.0.1"
+ }
+ },
+ "minipass": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz",
+ "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ=="
+ },
+ "signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="
}
}
},
@@ -94002,6 +93254,24 @@
}
}
},
+ "temp": {
+ "version": "0.8.4",
+ "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz",
+ "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==",
+ "requires": {
+ "rimraf": "~2.6.2"
+ },
+ "dependencies": {
+ "rimraf": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+ "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
+ }
+ },
"temp-dir": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz",
@@ -94210,6 +93480,14 @@
"minimatch": "^3.0.4"
}
},
+ "text-segmentation": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
+ "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
+ "requires": {
+ "utrie": "^1.0.2"
+ }
+ },
"text-table": {
"version": "0.2.0"
},
@@ -94487,9 +93765,9 @@
}
},
"traverse": {
- "version": "0.6.7",
- "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz",
- "integrity": "sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg=="
+ "version": "0.6.8",
+ "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.8.tgz",
+ "integrity": "sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA=="
},
"tree-kill": {
"version": "1.2.2",
@@ -94747,22 +94025,6 @@
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.35.tgz",
"integrity": "sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g=="
},
- "uglify-es": {
- "version": "3.3.9",
- "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz",
- "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==",
- "requires": {
- "commander": "~2.13.0",
- "source-map": "~0.6.1"
- },
- "dependencies": {
- "commander": {
- "version": "2.13.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz",
- "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA=="
- }
- }
- },
"uglify-js": {
"version": "3.17.4",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
@@ -95193,12 +94455,6 @@
"tslib": "^2.0.0"
}
},
- "use-sync-external-store": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
- "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
- "requires": {}
- },
"utf8": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz",
@@ -95250,6 +94506,14 @@
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
},
+ "utrie": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
+ "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
+ "requires": {
+ "base64-arraybuffer": "^1.0.2"
+ }
+ },
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
@@ -95689,6 +94953,29 @@
"defaults": "^1.0.3"
}
},
+ "web-encoding": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz",
+ "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==",
+ "requires": {
+ "@zxing/text-encoding": "0.9.0",
+ "util": "^0.12.3"
+ },
+ "dependencies": {
+ "util": {
+ "version": "0.12.5",
+ "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
+ "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==",
+ "requires": {
+ "inherits": "^2.0.3",
+ "is-arguments": "^1.0.4",
+ "is-generator-function": "^1.0.7",
+ "is-typed-array": "^1.1.3",
+ "which-typed-array": "^1.1.2"
+ }
+ }
+ }
+ },
"web-namespaces": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz",
@@ -96363,7 +95650,6 @@
"version": "npm:wrap-ansi@7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
"requires": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
@@ -96374,7 +95660,6 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
"requires": {
"color-convert": "^2.0.1"
}
@@ -96383,7 +95668,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
"requires": {
"color-name": "~1.1.4"
}
@@ -96391,8 +95675,7 @@
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
}
}
},
diff --git a/package.json b/package.json
index 29ade80b518d..a5823e18e357 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "1.4.21-4",
+ "version": "1.4.25-1",
"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.",
@@ -13,10 +13,10 @@
"postinstall": "scripts/postInstall.sh",
"clean": "npx react-native clean-project-auto",
"android": "scripts/set-pusher-suffix.sh && npx react-native run-android --mode=developmentDebug --appId=com.expensify.chat.dev",
- "ios": "scripts/set-pusher-suffix.sh && npx react-native run-ios --list-devices --configuration=\"DebugDevelopment\" --scheme=\"New Expensify Dev\"",
+ "ios": "scripts/set-pusher-suffix.sh && npx react-native run-ios --list-devices --mode=\"DebugDevelopment\" --scheme=\"New Expensify Dev\"",
"pod-install": "cd ios && bundle exec pod install",
- "ipad": "concurrently \"npx react-native run-ios --simulator=\\\"iPad Pro (12.9-inch) (6th generation)\\\" --configuration=\\\"DebugDevelopment\\\" --scheme=\\\"New Expensify Dev\\\"\"",
- "ipad-sm": "concurrently \"npx react-native run-ios --simulator=\\\"iPad Pro (11-inch) (4th generation)\\\" --configuration=\\\"DebugDevelopment\\\" --scheme=\\\"New Expensify Dev\\\"\"",
+ "ipad": "concurrently \"npx react-native run-ios --simulator=\\\"iPad Pro (12.9-inch) (6th generation)\\\" --mode=\\\"DebugDevelopment\\\" --scheme=\\\"New Expensify Dev\\\"\"",
+ "ipad-sm": "concurrently \"npx react-native run-ios --simulator=\\\"iPad Pro (11-inch) (4th generation)\\\" --mode=\\\"DebugDevelopment\\\" --scheme=\\\"New Expensify Dev\\\"\"",
"start": "npx react-native start",
"web": "scripts/set-pusher-suffix.sh && concurrently npm:web-proxy npm:web-server",
"web-proxy": "node web/proxy.js",
@@ -71,23 +71,23 @@
"@kie/mock-github": "^1.0.0",
"@oguzhnatly/react-native-image-manipulator": "github:Expensify/react-native-image-manipulator#5cdae3d4455b03a04c57f50be3863e2fe6c92c52",
"@onfido/react-native-sdk": "8.3.0",
- "@react-native-async-storage/async-storage": "^1.17.10",
+ "@react-native-async-storage/async-storage": "^1.19.5",
"@react-native-camera-roll/camera-roll": "5.4.0",
"@react-native-clipboard/clipboard": "^1.12.1",
"@react-native-community/geolocation": "^3.0.6",
- "@react-native-community/netinfo": "^9.3.10",
+ "@react-native-community/netinfo": "11.2.1",
"@react-native-firebase/analytics": "^12.3.0",
"@react-native-firebase/app": "^12.3.0",
"@react-native-firebase/crashlytics": "^12.3.0",
"@react-native-firebase/perf": "^12.3.0",
"@react-native-google-signin/google-signin": "^10.0.1",
- "@react-native-picker/picker": "^2.4.3",
+ "@react-native-picker/picker": "2.5.1",
"@react-navigation/material-top-tabs": "^6.6.3",
"@react-navigation/native": "6.1.8",
"@react-navigation/stack": "6.3.16",
"@react-ng/bounds-observer": "^0.2.1",
"@rnmapbox/maps": "^10.0.11",
- "@shopify/flash-list": "^1.6.1",
+ "@shopify/flash-list": "^1.6.3",
"@types/node": "^18.14.0",
"@ua/react-native-airship": "^15.3.1",
"@vue/preload-webpack-plugin": "^2.0.0",
@@ -99,16 +99,16 @@
"date-fns-tz": "^2.0.0",
"dom-serializer": "^0.2.2",
"domhandler": "^4.3.0",
- "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#398bf7c6a6d37f229a41d92bd7a4324c0fd32849",
- "expo": "^49.0.0",
- "expo-image": "1.8.1",
+ "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#c6bb3cfa56d12af9fa02e2bfc729646f5b64ef44",
+ "expo": "^50.0.0-preview.7",
+ "expo-image": "1.10.1",
"fbjs": "^3.0.2",
"htmlparser2": "^7.2.0",
"idb-keyval": "^6.2.1",
- "jest-expo": "^49.0.0",
+ "jest-expo": "50.0.1",
"jest-when": "^3.5.2",
"lodash": "4.17.21",
- "lottie-react-native": "^6.4.0",
+ "lottie-react-native": "6.4.1",
"mapbox-gl": "^2.15.0",
"onfido-sdk-ui": "13.1.0",
"patch-package": "^8.0.0",
@@ -122,7 +122,7 @@
"react-dom": "18.1.0",
"react-error-boundary": "^4.0.11",
"react-map-gl": "^7.1.3",
- "react-native": "0.72.4",
+ "react-native": "0.73.2",
"react-native-android-location-enabler": "^1.2.2",
"react-native-blob-util": "^0.17.3",
"react-native-collapsible": "^1.6.1",
@@ -132,7 +132,7 @@
"react-native-document-picker": "^8.2.1",
"react-native-draggable-flatlist": "^4.0.1",
"react-native-fs": "^2.20.0",
- "react-native-gesture-handler": "2.12.0",
+ "react-native-gesture-handler": "2.14.0",
"react-native-google-places-autocomplete": "2.5.6",
"react-native-haptic-feedback": "^1.13.0",
"react-native-image-pan-zoom": "^2.1.12",
@@ -142,9 +142,9 @@
"react-native-linear-gradient": "^2.8.1",
"react-native-localize": "^2.2.6",
"react-native-modal": "^13.0.0",
- "react-native-onyx": "1.0.118",
- "react-native-pager-view": "^6.2.0",
- "react-native-pdf": "^6.7.3",
+ "react-native-onyx": "1.0.126",
+ "react-native-pager-view": "6.2.2",
+ "react-native-pdf": "^6.7.4",
"react-native-performance": "^5.1.0",
"react-native-permissions": "^3.9.3",
"react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#7a407cd4174d9838a944c1c2e1cb4a9737ac69c5",
@@ -153,16 +153,16 @@
"react-native-quick-sqlite": "^8.0.0-beta.2",
"react-native-reanimated": "^3.6.1",
"react-native-render-html": "6.3.1",
- "react-native-safe-area-context": "4.4.1",
- "react-native-screens": "3.21.0",
- "react-native-svg": "^13.13.0",
+ "react-native-safe-area-context": "4.7.4",
+ "react-native-screens": "3.29.0",
+ "react-native-svg": "14.0.0",
"react-native-tab-view": "^3.5.2",
"react-native-url-polyfill": "^2.0.0",
- "react-native-view-shot": "^3.6.0",
+ "react-native-view-shot": "3.8.0",
"react-native-vision-camera": "^2.16.2",
"react-native-web": "^0.19.9",
"react-native-web-linear-gradient": "^1.1.2",
- "react-native-webview": "^11.17.2",
+ "react-native-webview": "13.6.3",
"react-pdf": "^6.2.2",
"react-plaid-link": "3.3.2",
"react-web-config": "^1.0.0",
@@ -195,7 +195,8 @@
"@octokit/plugin-paginate-rest": "3.1.0",
"@octokit/plugin-throttling": "4.1.0",
"@react-native-community/eslint-config": "3.0.0",
- "@react-native/metro-config": "^0.72.11",
+ "@react-native/babel-preset": "^0.73.19",
+ "@react-native/metro-config": "^0.73.3",
"@react-navigation/devtools": "^6.0.10",
"@storybook/addon-a11y": "^6.5.9",
"@storybook/addon-essentials": "^7.0.0",
@@ -209,6 +210,7 @@
"@testing-library/jest-native": "5.4.1",
"@testing-library/react-native": "11.5.1",
"@trivago/prettier-plugin-sort-imports": "^4.2.0",
+ "@types/canvas-size": "^1.2.2",
"@types/concurrently": "^7.0.0",
"@types/jest": "^29.5.2",
"@types/jest-when": "^3.5.2",
@@ -216,7 +218,7 @@
"@types/lodash": "^4.14.195",
"@types/mapbox-gl": "^2.7.13",
"@types/pusher-js": "^5.1.0",
- "@types/react": "^18.2.12",
+ "@types/react": "18.2.45",
"@types/react-beautiful-dnd": "^13.1.4",
"@types/react-collapse": "^5.0.1",
"@types/react-dom": "^18.2.4",
@@ -264,13 +266,11 @@
"jest-environment-jsdom": "^29.4.1",
"jest-transformer-svg": "^2.0.1",
"memfs": "^4.6.0",
- "metro-react-native-babel-preset": "0.76.8",
"onchange": "^7.1.0",
"portfinder": "^1.0.28",
"prettier": "^2.8.8",
"pusher-js-mock": "^0.3.3",
"react-native-clean-project": "^4.0.0-alpha4.0",
- "react-native-flipper": "https://gitpkg.now.sh/facebook/flipper/react-native/react-native-flipper?9cacc9b59402550eae866e0e81e5f0c2f8203e6b",
"react-native-performance-flipper-reporter": "^2.0.0",
"react-test-renderer": "18.2.0",
"reassure": "^0.10.1",
@@ -289,7 +289,9 @@
"yaml": "^2.2.1"
},
"overrides": {
- "react-native": "$react-native"
+ "react-native": "$react-native",
+ "expo": "$expo",
+ "react-native-svg": "$react-native-svg"
},
"expo": {
"autolinking": {
diff --git a/patches/@onfido+react-native-sdk+8.3.0.patch b/patches/@onfido+react-native-sdk+8.3.0.patch
index 12245cb58355..5d3fd51bf826 100644
--- a/patches/@onfido+react-native-sdk+8.3.0.patch
+++ b/patches/@onfido+react-native-sdk+8.3.0.patch
@@ -1,8 +1,22 @@
diff --git a/node_modules/@onfido/react-native-sdk/android/build.gradle b/node_modules/@onfido/react-native-sdk/android/build.gradle
-index b4c7106..d5083d3 100644
+index b4c7106..c6efb0f 100644
--- a/node_modules/@onfido/react-native-sdk/android/build.gradle
+++ b/node_modules/@onfido/react-native-sdk/android/build.gradle
-@@ -135,9 +135,9 @@ afterEvaluate { project ->
+@@ -84,6 +84,13 @@ android {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
++
++ publishing {
++ singleVariant('release') {
++ withSourcesJar()
++ withJavadocJar()
++ }
++ }
+ }
+
+ repositories {
+@@ -135,9 +142,9 @@ afterEvaluate { project ->
group = "Reporting"
description = "Generate Jacoco coverage reports after running tests."
reports {
diff --git a/patches/expo-image+1.10.1+001+applyFill.patch b/patches/expo-image+1.10.1+001+applyFill.patch
new file mode 100644
index 000000000000..5f168040d04d
--- /dev/null
+++ b/patches/expo-image+1.10.1+001+applyFill.patch
@@ -0,0 +1,112 @@
+diff --git a/node_modules/expo-image/android/src/main/java/com/caverock/androidsvg/SVGStyler.kt b/node_modules/expo-image/android/src/main/java/com/caverock/androidsvg/SVGStyler.kt
+index 619daf2..b58a0df 100644
+--- a/node_modules/expo-image/android/src/main/java/com/caverock/androidsvg/SVGStyler.kt
++++ b/node_modules/expo-image/android/src/main/java/com/caverock/androidsvg/SVGStyler.kt
+@@ -1,5 +1,9 @@
+ package com.caverock.androidsvg
+
++import com.caverock.androidsvg.SVG.SPECIFIED_COLOR
++import com.caverock.androidsvg.SVG.SPECIFIED_FILL
++import com.caverock.androidsvg.SVG.SvgElementBase
++
+ internal fun replaceColor(paint: SVG.SvgPaint?, newColor: Int) {
+ if (paint is SVG.Colour && paint !== SVG.Colour.TRANSPARENT) {
+ paint.colour = newColor
+@@ -19,15 +23,83 @@ internal fun replaceStyles(style: SVG.Style?, newColor: Int) {
+ replaceColor(style.viewportFill, newColor)
+ }
+
+-internal fun applyTintColor(element: SVG.SvgObject, newColor: Int) {
+- if (element is SVG.SvgElementBase) {
++internal fun hasStyle(element: SvgElementBase): Boolean {
++ if (element.style == null && element.baseStyle == null) {
++ return false
++ }
++
++ val style = element.style
++ val hasColorInStyle = style != null &&
++ (
++ style.color != null || style.fill != null || style.stroke != null ||
++ style.stroke != null || style.stopColor != null || style.solidColor != null
++ )
++
++ if (hasColorInStyle) {
++ return true
++ }
++
++ val baseStyle = element.baseStyle ?: return false
++ return baseStyle.color != null || baseStyle.fill != null || baseStyle.stroke != null ||
++ baseStyle.viewportFill != null || baseStyle.stopColor != null || baseStyle.solidColor != null
++}
++
++internal fun defineStyles(element: SvgElementBase, newColor: Int, hasStyle: Boolean) {
++ if (hasStyle) {
++ return
++ }
++
++ val style = if (element.style != null) {
++ element.style
++ } else {
++ SVG.Style().also {
++ element.style = it
++ }
++ }
++
++ val color = SVG.Colour(newColor)
++ when (element) {
++ is SVG.Path,
++ is SVG.Circle,
++ is SVG.Ellipse,
++ is SVG.Rect,
++ is SVG.SolidColor,
++ is SVG.Line,
++ is SVG.Polygon,
++ is SVG.PolyLine -> {
++ style.apply {
++ fill = color
++
++ specifiedFlags = SPECIFIED_FILL
++ }
++ }
++
++ is SVG.TextPath -> {
++ style.apply {
++ this.color = color
++
++ specifiedFlags = SPECIFIED_COLOR
++ }
++ }
++ }
++}
++
++internal fun applyTintColor(element: SVG.SvgObject, newColor: Int, parentDefinesStyle: Boolean) {
++ val definesStyle = if (element is SvgElementBase) {
++ val hasStyle = parentDefinesStyle || hasStyle(element)
++
+ replaceStyles(element.baseStyle, newColor)
+ replaceStyles(element.style, newColor)
++ defineStyles(element, newColor, hasStyle)
++
++ hasStyle
++ } else {
++ parentDefinesStyle
+ }
+
+ if (element is SVG.SvgContainer) {
+ for (child in element.children) {
+- applyTintColor(child, newColor)
++ applyTintColor(child, newColor, definesStyle)
+ }
+ }
+ }
+@@ -36,8 +108,9 @@ fun applyTintColor(svg: SVG, newColor: Int) {
+ val root = svg.rootElement
+
+ replaceStyles(root.style, newColor)
++ val hasStyle = hasStyle(root)
+
+ for (child in root.children) {
+- applyTintColor(child, newColor)
++ applyTintColor(child, newColor, hasStyle)
+ }
+ }
diff --git a/patches/expo-image+1.10.1+002+TintFix.patch b/patches/expo-image+1.10.1+002+TintFix.patch
new file mode 100644
index 000000000000..92b56c039b43
--- /dev/null
+++ b/patches/expo-image+1.10.1+002+TintFix.patch
@@ -0,0 +1,38 @@
+diff --git a/node_modules/expo-image/android/src/main/java/com/caverock/androidsvg/SVGStyler.kt b/node_modules/expo-image/android/src/main/java/com/caverock/androidsvg/SVGStyler.kt
+index b58a0df..6b8da3c 100644
+--- a/node_modules/expo-image/android/src/main/java/com/caverock/androidsvg/SVGStyler.kt
++++ b/node_modules/expo-image/android/src/main/java/com/caverock/androidsvg/SVGStyler.kt
+@@ -107,6 +107,7 @@ internal fun applyTintColor(element: SVG.SvgObject, newColor: Int, parentDefines
+ fun applyTintColor(svg: SVG, newColor: Int) {
+ val root = svg.rootElement
+
++ replaceStyles(root.baseStyle, newColor)
+ replaceStyles(root.style, newColor)
+ val hasStyle = hasStyle(root)
+
+diff --git a/node_modules/expo-image/android/src/main/java/expo/modules/image/ExpoImageViewWrapper.kt b/node_modules/expo-image/android/src/main/java/expo/modules/image/ExpoImageViewWrapper.kt
+index 602b570..8becf72 100644
+--- a/node_modules/expo-image/android/src/main/java/expo/modules/image/ExpoImageViewWrapper.kt
++++ b/node_modules/expo-image/android/src/main/java/expo/modules/image/ExpoImageViewWrapper.kt
+@@ -31,6 +31,7 @@ import expo.modules.image.records.ImageLoadEvent
+ import expo.modules.image.records.ImageProgressEvent
+ import expo.modules.image.records.ImageTransition
+ import expo.modules.image.records.SourceMap
++import expo.modules.image.svg.SVGPictureDrawable
+ import expo.modules.kotlin.AppContext
+ import expo.modules.kotlin.tracing.beginAsyncTraceBlock
+ import expo.modules.kotlin.tracing.trace
+@@ -127,7 +128,12 @@ class ExpoImageViewWrapper(context: Context, appContext: AppContext) : ExpoView(
+ internal var tintColor: Int? = null
+ set(value) {
+ field = value
+- activeView.setTintColor(value)
++ // To apply the tint color to the SVG, we need to recreate the drawable.
++ if (activeView.drawable is SVGPictureDrawable) {
++ shouldRerender = true
++ } else {
++ activeView.setTintColor(value)
++ }
+ }
+
+ internal var isFocusableProp: Boolean = false
diff --git a/patches/react-native+0.72.4+001+initial.patch b/patches/react-native+0.72.4+001+initial.patch
deleted file mode 100644
index f81762d83c1a..000000000000
--- a/patches/react-native+0.72.4+001+initial.patch
+++ /dev/null
@@ -1,83 +0,0 @@
-diff --git a/node_modules/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js b/node_modules/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js
-index 9fb5637..e26d677 100644
---- a/node_modules/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js
-+++ b/node_modules/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js
-@@ -65,6 +65,7 @@ class KeyboardAvoidingView extends React.Component {
- _subscriptions: Array = [];
- viewRef: {current: React.ElementRef | null, ...};
- _initialFrameHeight: number = 0;
-+ _bottom: number = 0;
-
- constructor(props: Props) {
- super(props);
-@@ -112,14 +113,15 @@ class KeyboardAvoidingView extends React.Component {
- };
-
- _onLayout = async (event: ViewLayoutEvent) => {
-- const wasFrameNull = this._frame == null;
-+ const oldFrame = this._frame;
- this._frame = event.nativeEvent.layout;
- if (!this._initialFrameHeight) {
- // save the initial frame height, before the keyboard is visible
- this._initialFrameHeight = this._frame.height;
- }
-
-- if (wasFrameNull) {
-+ // update bottom height for the first time or when the height is changed
-+ if (!oldFrame || oldFrame.height !== this._frame.height) {
- await this._updateBottomIfNecessary();
- }
-
-@@ -128,20 +130,32 @@ class KeyboardAvoidingView extends React.Component {
- }
- };
-
-+ // Avoid unnecessary renders if the KeyboardAvoidingView is disabled.
-+ _setBottom = (value: number) => {
-+ const enabled = this.props.enabled ?? true;
-+ this._bottom = value;
-+ if (enabled) {
-+ this.setState({bottom: value});
-+ }
-+ };
-+
- _updateBottomIfNecessary = async () => {
- if (this._keyboardEvent == null) {
-- this.setState({bottom: 0});
-+ this._setBottom(0);
- return;
- }
-
- const {duration, easing, endCoordinates} = this._keyboardEvent;
- const height = await this._relativeKeyboardHeight(endCoordinates);
-
-- if (this.state.bottom === height) {
-+ if (this._bottom === height) {
- return;
- }
-
-- if (duration && easing) {
-+ this._setBottom(height);
-+
-+ const enabled = this.props.enabled ?? true;
-+ if (enabled && duration && easing) {
- LayoutAnimation.configureNext({
- // We have to pass the duration equal to minimal accepted duration defined here: RCTLayoutAnimation.m
- duration: duration > 10 ? duration : 10,
-@@ -151,9 +165,15 @@ class KeyboardAvoidingView extends React.Component {
- },
- });
- }
-- this.setState({bottom: height});
- };
-
-+ componentDidUpdate(_: Props, prevState: State): void {
-+ const enabled = this.props.enabled ?? true;
-+ if (enabled && this._bottom !== prevState.bottom) {
-+ this.setState({bottom: this._bottom});
-+ }
-+ }
-+
- componentDidMount(): void {
- if (Platform.OS === 'ios') {
- this._subscriptions = [
diff --git a/patches/react-native+0.72.4+002+NumberOfLines.patch b/patches/react-native+0.73.2+001+NumberOfLines.patch
similarity index 88%
rename from patches/react-native+0.72.4+002+NumberOfLines.patch
rename to patches/react-native+0.73.2+001+NumberOfLines.patch
index 75422f84708e..c9ce92f8e1ef 100644
--- a/patches/react-native+0.72.4+002+NumberOfLines.patch
+++ b/patches/react-native+0.73.2+001+NumberOfLines.patch
@@ -17,7 +17,7 @@ index 55b770d..4073836 100644
* When `false`, if there is a small amount of space available around a text input
* (e.g. landscape orientation on a phone), the OS may choose to have the user edit
diff --git a/node_modules/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js b/node_modules/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js
-index 6f69329..d531bee 100644
+index 88d3cc8..664d37d 100644
--- a/node_modules/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js
+++ b/node_modules/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js
@@ -144,6 +144,8 @@ const RCTTextInputViewConfig = {
@@ -30,23 +30,10 @@ index 6f69329..d531bee 100644
maxLength: true,
autoCapitalize: 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 8badb2a..b19f197 100644
+index 2c0c099..5cb6bf1 100644
--- a/node_modules/react-native/Libraries/Components/TextInput/TextInput.d.ts
+++ b/node_modules/react-native/Libraries/Components/TextInput/TextInput.d.ts
-@@ -347,12 +347,6 @@ export interface TextInputAndroidProps {
- */
- inlineImagePadding?: number | undefined;
-
-- /**
-- * Sets the number of lines for a TextInput.
-- * Use it with multiline set to true to be able to fill the lines.
-- */
-- numberOfLines?: number | undefined;
--
- /**
- * Sets the return key to the label. Use it instead of `returnKeyType`.
- * @platform android
-@@ -663,11 +657,30 @@ export interface TextInputProps
+@@ -695,11 +695,29 @@ export interface TextInputProps
*/
maxLength?: number | undefined;
@@ -72,16 +59,15 @@ index 8badb2a..b19f197 100644
+ * Use it with multiline set to true to be able to fill the lines.
+ */
+ rows?: number | undefined;
-+
+
/**
* Callback that is called when the text input is blurred
*/
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 7ed4579..b1d994e 100644
+index 9adbfe9..dc52051 100644
--- a/node_modules/react-native/Libraries/Components/TextInput/TextInput.flow.js
+++ b/node_modules/react-native/Libraries/Components/TextInput/TextInput.flow.js
-@@ -343,26 +343,12 @@ type AndroidProps = $ReadOnly<{|
+@@ -366,26 +366,12 @@ type AndroidProps = $ReadOnly<{|
*/
inlineImagePadding?: ?number,
@@ -108,9 +94,9 @@ index 7ed4579..b1d994e 100644
/**
* When `false`, it will prevent the soft keyboard from showing when the field is focused.
* Defaults to `true`.
-@@ -632,6 +618,12 @@ export type Props = $ReadOnly<{|
+@@ -680,12 +666,24 @@ export type Props = $ReadOnly<{|
*/
- keyboardType?: ?KeyboardType,
+ maxLength?: ?number,
+ /**
+ * Sets the maximum number of lines for a `TextInput`. Use it with multiline set to
@@ -119,9 +105,8 @@ index 7ed4579..b1d994e 100644
+ maxNumberOfLines?: ?number,
+
/**
- * Specifies largest possible scale a font can reach when `allowFontScaling` is enabled.
- * Possible values:
-@@ -653,6 +645,12 @@ export type Props = $ReadOnly<{|
+ * If `true`, the text input can be multiple lines.
+ * The default value is `false`.
*/
multiline?: ?boolean,
@@ -134,7 +119,7 @@ index 7ed4579..b1d994e 100644
/**
* Callback that is called when the text input is blurred.
*/
-@@ -814,6 +812,12 @@ export type Props = $ReadOnly<{|
+@@ -847,6 +845,13 @@ export type Props = $ReadOnly<{|
*/
returnKeyType?: ?ReturnKeyType,
@@ -143,15 +128,16 @@ index 7ed4579..b1d994e 100644
+ * `true` to be able to fill the lines.
+ */
+ rows?: ?number,
++
+
/**
* If `true`, the text input obscures the text entered so that sensitive text
* like passwords stay secure. The default value is `false`. Does not work with 'multiline={true}'.
diff --git a/node_modules/react-native/Libraries/Components/TextInput/TextInput.js b/node_modules/react-native/Libraries/Components/TextInput/TextInput.js
-index 2127191..542fc06 100644
+index 481938f..3ce7422 100644
--- a/node_modules/react-native/Libraries/Components/TextInput/TextInput.js
+++ b/node_modules/react-native/Libraries/Components/TextInput/TextInput.js
-@@ -390,7 +390,6 @@ type AndroidProps = $ReadOnly<{|
+@@ -413,7 +413,6 @@ type AndroidProps = $ReadOnly<{|
/**
* Sets the number of lines for a `TextInput`. Use it with multiline set to
* `true` to be able to fill the lines.
@@ -159,7 +145,7 @@ index 2127191..542fc06 100644
*/
numberOfLines?: ?number,
-@@ -403,10 +402,14 @@ type AndroidProps = $ReadOnly<{|
+@@ -426,10 +425,15 @@ type AndroidProps = $ReadOnly<{|
/**
* Sets the number of rows for a `TextInput`. Use it with multiline set to
* `true` to be able to fill the lines.
@@ -171,11 +157,12 @@ index 2127191..542fc06 100644
+ * Sets the maximum number of lines the TextInput can have.
+ */
+ maxNumberOfLines?: ?number,
++
+
/**
* When `false`, it will prevent the soft keyboard from showing when the field is focused.
* Defaults to `true`.
-@@ -1069,6 +1072,9 @@ function InternalTextInput(props: Props): React.Node {
+@@ -1102,6 +1106,9 @@ function InternalTextInput(props: Props): React.Node {
accessibilityState,
id,
tabIndex,
@@ -185,7 +172,7 @@ index 2127191..542fc06 100644
selection: propsSelection,
...otherProps
} = props;
-@@ -1427,6 +1433,8 @@ function InternalTextInput(props: Props): React.Node {
+@@ -1460,6 +1467,8 @@ function InternalTextInput(props: Props): React.Node {
focusable={tabIndex !== undefined ? !tabIndex : focusable}
mostRecentEventCount={mostRecentEventCount}
nativeID={id ?? props.nativeID}
@@ -194,7 +181,7 @@ index 2127191..542fc06 100644
onBlur={_onBlur}
onKeyPressSync={props.unstable_onKeyPressSync}
onChange={_onChange}
-@@ -1482,6 +1490,7 @@ function InternalTextInput(props: Props): React.Node {
+@@ -1515,6 +1524,7 @@ function InternalTextInput(props: Props): React.Node {
mostRecentEventCount={mostRecentEventCount}
nativeID={id ?? props.nativeID}
numberOfLines={props.rows ?? props.numberOfLines}
@@ -203,11 +190,11 @@ index 2127191..542fc06 100644
onChange={_onChange}
onFocus={_onFocus}
diff --git a/node_modules/react-native/Libraries/Text/Text.js b/node_modules/react-native/Libraries/Text/Text.js
-index df548af..e02f5da 100644
+index d737ccc..beee7ce 100644
--- a/node_modules/react-native/Libraries/Text/Text.js
+++ b/node_modules/react-native/Libraries/Text/Text.js
-@@ -18,7 +18,11 @@ import processColor from '../StyleSheet/processColor';
- import {getAccessibilityRoleFromRole} from '../Utilities/AcessibilityMapping';
+@@ -17,7 +17,11 @@ import flattenStyle from '../StyleSheet/flattenStyle';
+ import processColor from '../StyleSheet/processColor';
import Platform from '../Utilities/Platform';
import TextAncestor from './TextAncestor';
-import {NativeText, NativeVirtualText} from './TextNativeComponent';
@@ -219,15 +206,15 @@ index df548af..e02f5da 100644
import * as React from 'react';
import {useContext, useMemo, useState} from 'react';
-@@ -59,6 +63,7 @@ const Text: React.AbstractComponent<
+@@ -56,6 +60,7 @@ const Text: React.AbstractComponent<
+ onStartShouldSetResponder,
pressRetentionOffset,
- role,
suppressHighlighting,
+ numberOfLines,
...restProps
} = props;
-@@ -192,14 +197,33 @@ const Text: React.AbstractComponent<
+@@ -195,14 +200,34 @@ const Text: React.AbstractComponent<
}
}
@@ -259,11 +246,12 @@ index df548af..e02f5da 100644
+ maximumNumberOfLines: numberOfLinesValue,
+ };
+ }, [numberOfLinesValue]);
++
+
const hasTextAncestor = useContext(TextAncestor);
const _accessible = Platform.select({
-@@ -241,7 +265,6 @@ const Text: React.AbstractComponent<
+@@ -251,7 +276,6 @@ const Text: React.AbstractComponent<
isHighlighted={isHighlighted}
isPressable={isPressable}
nativeID={id ?? nativeID}
@@ -271,15 +259,15 @@ index df548af..e02f5da 100644
ref={forwardedRef}
selectable={_selectable}
selectionColor={selectionColor}
-@@ -252,6 +275,7 @@ const Text: React.AbstractComponent<
+@@ -262,6 +286,7 @@ const Text: React.AbstractComponent<
@@ -347,10 +335,10 @@ index 8f4cf7e..6238ebc 100644
@property (nonatomic, copy, nullable) RCTDirectEventBlock onContentSizeChange;
- (void)uiManagerWillPerformMounting;
-diff --git a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m
-index 04d2446..9d77743 100644
---- a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m
-+++ b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputShadowView.m
+diff --git a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputShadowView.mm b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputShadowView.mm
+index 1f06b79..48172ce 100644
+--- a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputShadowView.mm
++++ b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputShadowView.mm
@@ -218,7 +218,22 @@ - (NSAttributedString *)measurableAttributedText
- (CGSize)sizeThatFitsMinimumSize:(CGSize)minimumSize maximumSize:(CGSize)maximumSize
@@ -375,10 +363,10 @@ index 04d2446..9d77743 100644
if (!_textStorage) {
_textContainer = [NSTextContainer new];
-diff --git a/node_modules/react-native/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputViewManager.m b/node_modules/react-native/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputViewManager.m
+diff --git a/node_modules/react-native/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputViewManager.mm b/node_modules/react-native/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputViewManager.mm
index 413ac42..56d039c 100644
---- a/node_modules/react-native/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputViewManager.m
-+++ b/node_modules/react-native/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputViewManager.m
+--- a/node_modules/react-native/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputViewManager.mm
++++ b/node_modules/react-native/Libraries/Text/TextInput/Singleline/RCTSinglelineTextInputViewManager.mm
@@ -19,6 +19,7 @@ - (RCTShadowView *)shadowView
RCTBaseTextInputShadowView *shadowView = (RCTBaseTextInputShadowView *)[super shadowView];
@@ -442,7 +430,7 @@ index 8cab407..ad5fa96 100644
+ public static final int MAXIMUM_NUMBER_OF_LINES = Integer.MAX_VALUE;
}
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java
-index 3f76fa7..7a5d096 100644
+index fa6eae3..f524753 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java
@@ -96,6 +96,7 @@ public class ViewProps {
@@ -454,18 +442,18 @@ index 3f76fa7..7a5d096 100644
public static final String ADJUSTS_FONT_SIZE_TO_FIT = "adjustsFontSizeToFit";
public static final String MINIMUM_FONT_SCALE = "minimumFontScale";
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java
-index b5811c7..96eef96 100644
+index d2c2d6e..e4dec5d 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java
-@@ -303,6 +303,7 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
- protected boolean mIsAccessibilityLink = false;
+@@ -311,6 +311,7 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
+ protected @Nullable Role mRole = null;
protected int mNumberOfLines = UNSET;
+ protected int mMaxNumberOfLines = UNSET;
protected int mTextAlign = Gravity.NO_GRAVITY;
protected int mTextBreakStrategy =
(Build.VERSION.SDK_INT < Build.VERSION_CODES.M) ? 0 : Layout.BREAK_STRATEGY_HIGH_QUALITY;
-@@ -387,6 +388,12 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
+@@ -395,6 +396,12 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
markUpdated();
}
@@ -479,7 +467,7 @@ index b5811c7..96eef96 100644
public void setLineHeight(float lineHeight) {
mTextAttributes.setLineHeight(lineHeight);
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextAnchorViewManager.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextAnchorViewManager.java
-index 7b5d0c1..c3032eb 100644
+index f683c24..b5f6f7d 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextAnchorViewManager.java
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextAnchorViewManager.java
@@ -49,8 +49,8 @@ public abstract class ReactTextAnchorViewManager sSpannableCache =
new LruCache<>(spannableCacheSize);
private static final ConcurrentHashMap sTagToSpannableCache =
-@@ -385,6 +387,48 @@ public class TextLayoutManager {
+@@ -395,6 +397,48 @@ public class TextLayoutManager {
? paragraphAttributes.getInt(MAXIMUM_NUMBER_OF_LINES_KEY)
: UNSET;
@@ -619,10 +607,10 @@ index 561a2d0..9409cfc 100644
maximumNumberOfLines == UNSET || maximumNumberOfLines == 0
? layout.getLineCount()
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManagerMapBuffer.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManagerMapBuffer.java
-index 0d118f0..0ae44b7 100644
+index 8cd5764..35a2e9e 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManagerMapBuffer.java
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManagerMapBuffer.java
-@@ -18,6 +18,7 @@ import android.text.SpannableStringBuilder;
+@@ -20,6 +20,7 @@ import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.StaticLayout;
import android.text.TextPaint;
@@ -630,7 +618,7 @@ index 0d118f0..0ae44b7 100644
import android.util.LayoutDirection;
import android.util.LruCache;
import android.view.View;
-@@ -61,6 +62,7 @@ public class TextLayoutManagerMapBuffer {
+@@ -66,6 +67,7 @@ public class TextLayoutManagerMapBuffer {
public static final short PA_KEY_ADJUST_FONT_SIZE_TO_FIT = 3;
public static final short PA_KEY_INCLUDE_FONT_PADDING = 4;
public static final short PA_KEY_HYPHENATION_FREQUENCY = 5;
@@ -638,7 +626,7 @@ index 0d118f0..0ae44b7 100644
private static final boolean ENABLE_MEASURE_LOGGING = ReactBuildConfig.DEBUG && false;
-@@ -399,6 +401,47 @@ public class TextLayoutManagerMapBuffer {
+@@ -417,6 +419,46 @@ public class TextLayoutManagerMapBuffer {
? paragraphAttributes.getInt(PA_KEY_MAX_NUMBER_OF_LINES)
: UNSET;
@@ -681,29 +669,33 @@ index 0d118f0..0ae44b7 100644
+ if (numberOfLines != UNSET && numberOfLines != 0) {
+ maximumNumberOfLines = numberOfLines;
+ }
-+
+
int calculatedLineCount =
maximumNumberOfLines == UNSET || maximumNumberOfLines == 0
? layout.getLineCount()
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
-index ced37be..ef2f321 100644
+index 081f2b8..0659179 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
-@@ -548,7 +548,13 @@ public class ReactEditText extends AppCompatEditText
+@@ -546,9 +546,15 @@ public class ReactEditText extends AppCompatEditText {
+ * android.widget.TextView#isMultilineInputType(int)}} Source: {@Link TextView.java}
*/
- if (isMultiline()) {
-+ // we save max lines as setSingleLines overwrites it
-+ // https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/widget/TextView.java#10671
-+ int maxLines = getMaxLines();
- setSingleLine(false);
-+ if (maxLines != -1) {
-+ setMaxLines(maxLines);
-+ }
- }
+- if (isMultiline()) {
+- setSingleLine(false);
+- }
++ if (isMultiline()) {
++ // we save max lines as setSingleLines overwrites it
++ // https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/widget/TextView.java#10671
++ int maxLines = getMaxLines();
++ setSingleLine(false);
++ if (maxLines != -1) {
++ setMaxLines(maxLines);
++ }
++ }
// We override the KeyListener so that all keys on the soft input keyboard as well as hardware
+ // keyboards work. Some KeyListeners like DigitsKeyListener will display the keyboard but not
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputLocalData.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputLocalData.java
index a850510..c59be1d 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputLocalData.java
@@ -720,10 +712,10 @@ index a850510..c59be1d 100644
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
editText.setBreakStrategy(mBreakStrategy);
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
-index b27ace4..c6a2d63 100644
+index 8496a7d..e4d975b 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java
-@@ -737,9 +737,18 @@ public class ReactTextInputManager extends BaseViewManager= Build.VERSION_CODES.M
diff --git a/node_modules/react-native/ReactCommon/react/renderer/attributedstring/ParagraphAttributes.cpp b/node_modules/react-native/ReactCommon/react/renderer/attributedstring/ParagraphAttributes.cpp
-index 2994aca..fff0d5e 100644
+index f2317ba..10f342c 100644
--- a/node_modules/react-native/ReactCommon/react/renderer/attributedstring/ParagraphAttributes.cpp
+++ b/node_modules/react-native/ReactCommon/react/renderer/attributedstring/ParagraphAttributes.cpp
@@ -16,6 +16,7 @@ namespace facebook::react {
- bool ParagraphAttributes::operator==(const ParagraphAttributes &rhs) const {
+ bool ParagraphAttributes::operator==(const ParagraphAttributes& rhs) const {
return std::tie(
+ numberOfLines,
maximumNumberOfLines,
ellipsizeMode,
textBreakStrategy,
-@@ -23,6 +24,7 @@ bool ParagraphAttributes::operator==(const ParagraphAttributes &rhs) const {
+@@ -23,6 +24,7 @@ bool ParagraphAttributes::operator==(const ParagraphAttributes& rhs) const {
includeFontPadding,
android_hyphenationFrequency) ==
std::tie(
@@ -777,7 +769,7 @@ index 2994aca..fff0d5e 100644
rhs.maximumNumberOfLines,
rhs.ellipsizeMode,
rhs.textBreakStrategy,
-@@ -42,6 +44,7 @@ bool ParagraphAttributes::operator!=(const ParagraphAttributes &rhs) const {
+@@ -42,6 +44,7 @@ bool ParagraphAttributes::operator!=(const ParagraphAttributes& rhs) const {
#if RN_DEBUG_STRING_CONVERTIBLE
SharedDebugStringConvertibleList ParagraphAttributes::getDebugProps() const {
return {
@@ -786,10 +778,10 @@ index 2994aca..fff0d5e 100644
debugStringConvertibleItem("ellipsizeMode", ellipsizeMode),
debugStringConvertibleItem("textBreakStrategy", textBreakStrategy),
diff --git a/node_modules/react-native/ReactCommon/react/renderer/attributedstring/ParagraphAttributes.h b/node_modules/react-native/ReactCommon/react/renderer/attributedstring/ParagraphAttributes.h
-index f5f87c6..b7d1e90 100644
+index d73f863..1f85b22 100644
--- a/node_modules/react-native/ReactCommon/react/renderer/attributedstring/ParagraphAttributes.h
+++ b/node_modules/react-native/ReactCommon/react/renderer/attributedstring/ParagraphAttributes.h
-@@ -30,6 +30,11 @@ class ParagraphAttributes : public DebugStringConvertible {
+@@ -29,6 +29,11 @@ class ParagraphAttributes : public DebugStringConvertible {
public:
#pragma mark - Fields
@@ -801,20 +793,20 @@ index f5f87c6..b7d1e90 100644
/*
* Maximum number of lines which paragraph can take.
* Zero value represents "no limit".
-@@ -92,6 +97,7 @@ struct hash {
- const facebook::react::ParagraphAttributes &attributes) const {
- return folly::hash::hash_combine(
- 0,
+@@ -89,6 +94,7 @@ struct hash {
+ size_t operator()(
+ const facebook::react::ParagraphAttributes& attributes) const {
+ return facebook::react::hash_combine(
+ attributes.numberOfLines,
attributes.maximumNumberOfLines,
attributes.ellipsizeMode,
attributes.textBreakStrategy,
diff --git a/node_modules/react-native/ReactCommon/react/renderer/attributedstring/conversions.h b/node_modules/react-native/ReactCommon/react/renderer/attributedstring/conversions.h
-index 8687b89..eab75f4 100644
+index 445e452..3f0bb36 100644
--- a/node_modules/react-native/ReactCommon/react/renderer/attributedstring/conversions.h
+++ b/node_modules/react-native/ReactCommon/react/renderer/attributedstring/conversions.h
-@@ -835,10 +835,16 @@ inline ParagraphAttributes convertRawProp(
- ParagraphAttributes const &defaultParagraphAttributes) {
+@@ -692,10 +692,16 @@ inline ParagraphAttributes convertRawProp(
+ const ParagraphAttributes& defaultParagraphAttributes) {
auto paragraphAttributes = ParagraphAttributes{};
- paragraphAttributes.maximumNumberOfLines = convertRawProp(
@@ -831,23 +823,23 @@ index 8687b89..eab75f4 100644
sourceParagraphAttributes.maximumNumberOfLines,
defaultParagraphAttributes.maximumNumberOfLines);
paragraphAttributes.ellipsizeMode = convertRawProp(
-@@ -913,6 +919,7 @@ inline std::string toString(AttributedString::Range const &range) {
+@@ -770,6 +776,7 @@ inline std::string toString(const AttributedString::Range& range) {
inline folly::dynamic toDynamic(
- const ParagraphAttributes ¶graphAttributes) {
+ const ParagraphAttributes& paragraphAttributes) {
auto values = folly::dynamic::object();
+ values("numberOfLines", paragraphAttributes.numberOfLines);
values("maximumNumberOfLines", paragraphAttributes.maximumNumberOfLines);
values("ellipsizeMode", toString(paragraphAttributes.ellipsizeMode));
values("textBreakStrategy", toString(paragraphAttributes.textBreakStrategy));
-@@ -1118,6 +1125,7 @@ constexpr static MapBuffer::Key PA_KEY_TEXT_BREAK_STRATEGY = 2;
+@@ -979,6 +986,7 @@ constexpr static MapBuffer::Key PA_KEY_TEXT_BREAK_STRATEGY = 2;
constexpr static MapBuffer::Key PA_KEY_ADJUST_FONT_SIZE_TO_FIT = 3;
constexpr static MapBuffer::Key PA_KEY_INCLUDE_FONT_PADDING = 4;
constexpr static MapBuffer::Key PA_KEY_HYPHENATION_FREQUENCY = 5;
+constexpr static MapBuffer::Key PA_KEY_NUMBER_OF_LINES = 6;
- inline MapBuffer toMapBuffer(const ParagraphAttributes ¶graphAttributes) {
+ inline MapBuffer toMapBuffer(const ParagraphAttributes& paragraphAttributes) {
auto builder = MapBufferBuilder();
-@@ -1135,6 +1143,8 @@ inline MapBuffer toMapBuffer(const ParagraphAttributes ¶graphAttributes) {
+@@ -996,6 +1004,8 @@ inline MapBuffer toMapBuffer(const ParagraphAttributes& paragraphAttributes) {
builder.putString(
PA_KEY_HYPHENATION_FREQUENCY,
toString(paragraphAttributes.android_hyphenationFrequency));
@@ -857,7 +849,7 @@ index 8687b89..eab75f4 100644
return builder.build();
}
diff --git a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp
-index 9953e22..98eb3da 100644
+index 116284f..5749c57 100644
--- a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp
+++ b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp
@@ -56,6 +56,10 @@ AndroidTextInputProps::AndroidTextInputProps(
@@ -865,9 +857,9 @@ index 9953e22..98eb3da 100644
sourceProps.numberOfLines,
{0})),
+ maximumNumberOfLines(CoreFeatures::enablePropIteratorSetter? sourceProps.maximumNumberOfLines : convertRawProp(context, rawProps,
-+ "maximumNumberOfLines",
-+ sourceProps.maximumNumberOfLines,
-+ {0})),
++ "maximumNumberOfLines",
++ sourceProps.maximumNumberOfLines,
++ {0})),
disableFullscreenUI(CoreFeatures::enablePropIteratorSetter? sourceProps.disableFullscreenUI : convertRawProp(context, rawProps,
"disableFullscreenUI",
sourceProps.disableFullscreenUI,
@@ -901,10 +893,10 @@ index 9953e22..98eb3da 100644
props["returnKeyLabel"] = returnKeyLabel;
props["numberOfLines"] = numberOfLines;
diff --git a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.h b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.h
-index ba39ebb..ead28e3 100644
+index 43cbb68..0bf63e7 100644
--- a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.h
+++ b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.h
-@@ -84,6 +84,7 @@ class AndroidTextInputProps final : public ViewProps, public BaseTextProps {
+@@ -81,6 +81,7 @@ class AndroidTextInputProps final : public ViewProps, public BaseTextProps {
std::string autoComplete{};
std::string returnKeyLabel{};
int numberOfLines{0};
@@ -913,21 +905,20 @@ index ba39ebb..ead28e3 100644
std::string textBreakStrategy{};
SharedColor underlineColorAndroid{};
diff --git a/node_modules/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm b/node_modules/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm
-index 368c334..a1bb33e 100644
+index 368c334..ef9ec17 100644
--- a/node_modules/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm
+++ b/node_modules/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm
-@@ -244,26 +244,51 @@ - (void)getRectWithAttributedString:(AttributedString)attributedString
+@@ -244,26 +244,49 @@ - (void)getRectWithAttributedString:(AttributedString)attributedString
#pragma mark - Private
-- (NSTextStorage *)_textStorageForNSAttributesString:(NSAttributedString *)attributedString
-++- (NSTextStorage *)_textStorageForNSAttributesString:(NSAttributedString *)inputAttributedString
++- (NSTextStorage *)_textStorageForNSAttributesString:(NSAttributedString *)inputAttributedString
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
size:(CGSize)size
{
- NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:size];
-+ NSMutableAttributedString *attributedString = [ inputAttributedString mutableCopy];
-+
++NSMutableAttributedString *attributedString = [ inputAttributedString mutableCopy];
+ /*
+ * The block below is responsible for setting the exact height of the view in lines
+ * Unfortunatelly, iOS doesn't export any easy way to do it. So we set maximumNumberOfLines
@@ -969,9 +960,8 @@ index 368c334..a1bb33e 100644
+ : NSLineBreakByClipping;
+ textContainer.size = size;
+ textContainer.maximumNumberOfLines = paragraphAttributes.maximumNumberOfLines;
-+
++
+ [textStorage replaceCharactersInRange:(NSRange){0, textStorage.length} withAttributedString:attributedString];
-+
+
if (paragraphAttributes.adjustsFontSizeToFit) {
CGFloat minimumFontSize = !isnan(paragraphAttributes.minimumFontSize) ? paragraphAttributes.minimumFontSize : 4.0;
diff --git a/patches/react-native+0.72.4+004+ModalKeyboardFlashing.patch b/patches/react-native+0.73.2+001+initial.patch
similarity index 93%
rename from patches/react-native+0.72.4+004+ModalKeyboardFlashing.patch
rename to patches/react-native+0.73.2+001+initial.patch
index 84a233894f94..673013517e3d 100644
--- a/patches/react-native+0.72.4+004+ModalKeyboardFlashing.patch
+++ b/patches/react-native+0.73.2+001+initial.patch
@@ -2,7 +2,7 @@ diff --git a/node_modules/react-native/React/Views/RCTModalHostViewManager.m b/n
index 4b9f9ad..b72984c 100644
--- a/node_modules/react-native/React/Views/RCTModalHostViewManager.m
+++ b/node_modules/react-native/React/Views/RCTModalHostViewManager.m
-@@ -79,6 +79,13 @@ RCT_EXPORT_MODULE()
+@@ -79,6 +79,13 @@ - (void)presentModalHostView:(RCTModalHostView *)modalHostView
if (self->_presentationBlock) {
self->_presentationBlock([modalHostView reactViewController], viewController, animated, completionBlock);
} else {
diff --git a/patches/react-native-reanimated+3.6.1+001+fix-boost-dependency.patch b/patches/react-native-reanimated+3.6.1+001+fix-boost-dependency.patch
new file mode 100644
index 000000000000..9a98cb7af85f
--- /dev/null
+++ b/patches/react-native-reanimated+3.6.1+001+fix-boost-dependency.patch
@@ -0,0 +1,13 @@
+diff --git a/node_modules/react-native-reanimated/android/build.gradle b/node_modules/react-native-reanimated/android/build.gradle
+index 3de90e5..42d9d1a 100644
+--- a/node_modules/react-native-reanimated/android/build.gradle
++++ b/node_modules/react-native-reanimated/android/build.gradle
+@@ -567,7 +567,7 @@ if (REACT_NATIVE_MINOR_VERSION < 71) {
+ task downloadBoost(dependsOn: resolveBoost, type: Download) {
+ def transformedVersion = BOOST_VERSION.replace("_", ".")
+ def artifactLocalName = "boost_${BOOST_VERSION}.tar.gz"
+- def srcUrl = "https://boostorg.jfrog.io/artifactory/main/release/${transformedVersion}/source/${artifactLocalName}"
++ def srcUrl = "https://archives.boost.io/release/${transformedVersion}/source/${artifactLocalName}"
+ if (REACT_NATIVE_MINOR_VERSION < 69) {
+ srcUrl = "https://github.com/react-native-community/boost-for-react-native/releases/download/v${transformedVersion}-0/${artifactLocalName}"
+ }
diff --git a/patches/react-native-vision-camera+2.16.2+001+fix-boost-dependency.patch b/patches/react-native-vision-camera+2.16.2+001+fix-boost-dependency.patch
new file mode 100644
index 000000000000..ef4fbf1d5084
--- /dev/null
+++ b/patches/react-native-vision-camera+2.16.2+001+fix-boost-dependency.patch
@@ -0,0 +1,13 @@
+diff --git a/node_modules/react-native-vision-camera/android/build.gradle b/node_modules/react-native-vision-camera/android/build.gradle
+index d308e15..2d87d8e 100644
+--- a/node_modules/react-native-vision-camera/android/build.gradle
++++ b/node_modules/react-native-vision-camera/android/build.gradle
+@@ -347,7 +347,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/patches/react-native-vision-camera+2.16.2.patch b/patches/react-native-vision-camera+2.16.2.patch
new file mode 100644
index 000000000000..d08f7c11f5f3
--- /dev/null
+++ b/patches/react-native-vision-camera+2.16.2.patch
@@ -0,0 +1,13 @@
+diff --git a/node_modules/react-native-vision-camera/android/src/main/java/com/mrousavy/camera/frameprocessor/FrameProcessorRuntimeManager.kt b/node_modules/react-native-vision-camera/android/src/main/java/com/mrousavy/camera/frameprocessor/FrameProcessorRuntimeManager.kt
+index c0a8b23..653b51e 100644
+--- a/node_modules/react-native-vision-camera/android/src/main/java/com/mrousavy/camera/frameprocessor/FrameProcessorRuntimeManager.kt
++++ b/node_modules/react-native-vision-camera/android/src/main/java/com/mrousavy/camera/frameprocessor/FrameProcessorRuntimeManager.kt
+@@ -40,7 +40,7 @@ class FrameProcessorRuntimeManager(context: ReactApplicationContext, frameProces
+ val holder = context.catalystInstance.jsCallInvokerHolder as CallInvokerHolderImpl
+ mScheduler = VisionCameraScheduler(frameProcessorThread)
+ mContext = WeakReference(context)
+- mHybridData = initHybrid(context.javaScriptContextHolder.get(), holder, mScheduler!!)
++ mHybridData = initHybrid(context.javaScriptContextHolder!!.get(), holder, mScheduler!!)
+ initializeRuntime()
+
+ Log.i(TAG, "Installing JSI Bindings on JS Thread...")
diff --git a/patches/react-native-web+0.19.9+001+initial.patch b/patches/react-native-web+0.19.9+001+initial.patch
index d88ef83d4bcd..91ba6bfd59c0 100644
--- a/patches/react-native-web+0.19.9+001+initial.patch
+++ b/patches/react-native-web+0.19.9+001+initial.patch
@@ -1,286 +1,648 @@
diff --git a/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js b/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js
-index c879838..288316c 100644
+index c879838..0c9dfcb 100644
--- a/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js
+++ b/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js
-@@ -117,6 +117,14 @@ function findLastWhere(arr, predicate) {
- *
- */
- class VirtualizedList extends StateSafePureComponent {
-+ pushOrUnshift(input, item) {
-+ if (this.props.inverted) {
-+ input.unshift(item);
-+ } else {
-+ input.push(item);
+@@ -285,7 +285,7 @@ class VirtualizedList extends StateSafePureComponent {
+ // $FlowFixMe[missing-local-annot]
+
+ constructor(_props) {
+- var _this$props$updateCel;
++ var _this$props$updateCel, _this$props$maintainV, _this$props$maintainV2;
+ super(_props);
+ this._getScrollMetrics = () => {
+ return this._scrollMetrics;
+@@ -520,6 +520,11 @@ class VirtualizedList extends StateSafePureComponent {
+ visibleLength,
+ zoomScale
+ };
++ if (this.state.pendingScrollUpdateCount > 0) {
++ this.setState(state => ({
++ pendingScrollUpdateCount: state.pendingScrollUpdateCount - 1
++ }));
++ }
+ this._updateViewableItems(this.props, this.state.cellsAroundViewport);
+ if (!this.props) {
+ return;
+@@ -569,7 +574,7 @@ class VirtualizedList extends StateSafePureComponent {
+ this._updateCellsToRender = () => {
+ this._updateViewableItems(this.props, this.state.cellsAroundViewport);
+ this.setState((state, props) => {
+- var cellsAroundViewport = this._adjustCellsAroundViewport(props, state.cellsAroundViewport);
++ var cellsAroundViewport = this._adjustCellsAroundViewport(props, state.cellsAroundViewport, state.pendingScrollUpdateCount);
+ var renderMask = VirtualizedList._createRenderMask(props, cellsAroundViewport, this._getNonViewportRenderRegions(props));
+ if (cellsAroundViewport.first === state.cellsAroundViewport.first && cellsAroundViewport.last === state.cellsAroundViewport.last && renderMask.equals(state.renderMask)) {
+ return null;
+@@ -589,7 +594,7 @@ class VirtualizedList extends StateSafePureComponent {
+ return {
+ index,
+ item,
+- key: this._keyExtractor(item, index, props),
++ key: VirtualizedList._keyExtractor(item, index, props),
+ isViewable
+ };
+ };
+@@ -621,12 +626,10 @@ class VirtualizedList extends StateSafePureComponent {
+ };
+ this._getFrameMetrics = (index, props) => {
+ var data = props.data,
+- getItem = props.getItem,
+ getItemCount = props.getItemCount,
+ getItemLayout = props.getItemLayout;
+ invariant(index >= 0 && index < getItemCount(data), 'Tried to get frame for out of range index ' + index);
+- var item = getItem(data, index);
+- var frame = this._frames[this._keyExtractor(item, index, props)];
++ var frame = this._frames[VirtualizedList._getItemKey(props, index)];
+ if (!frame || frame.index !== index) {
+ if (getItemLayout) {
+ /* $FlowFixMe[prop-missing] (>=0.63.0 site=react_native_fb) This comment
+@@ -650,7 +653,7 @@ class VirtualizedList extends StateSafePureComponent {
+
+ // The last cell we rendered may be at a new index. Bail if we don't know
+ // where it is.
+- if (focusedCellIndex >= itemCount || this._keyExtractor(props.getItem(props.data, focusedCellIndex), focusedCellIndex, props) !== this._lastFocusedCellKey) {
++ if (focusedCellIndex >= itemCount || VirtualizedList._getItemKey(props, focusedCellIndex) !== this._lastFocusedCellKey) {
+ return [];
+ }
+ var first = focusedCellIndex;
+@@ -690,9 +693,15 @@ class VirtualizedList extends StateSafePureComponent {
+ }
+ }
+ var initialRenderRegion = VirtualizedList._initialRenderRegion(_props);
++ var minIndexForVisible = (_this$props$maintainV = (_this$props$maintainV2 = this.props.maintainVisibleContentPosition) == null ? void 0 : _this$props$maintainV2.minIndexForVisible) !== null && _this$props$maintainV !== void 0 ? _this$props$maintainV : 0;
+ this.state = {
+ cellsAroundViewport: initialRenderRegion,
+- renderMask: VirtualizedList._createRenderMask(_props, initialRenderRegion)
++ renderMask: VirtualizedList._createRenderMask(_props, initialRenderRegion),
++ firstVisibleItemKey: this.props.getItemCount(this.props.data) > minIndexForVisible ? VirtualizedList._getItemKey(this.props, minIndexForVisible) : null,
++ // When we have a non-zero initialScrollIndex, we will receive a
++ // scroll event later so this will prevent the window from updating
++ // until we get a valid offset.
++ pendingScrollUpdateCount: this.props.initialScrollIndex != null && this.props.initialScrollIndex > 0 ? 1 : 0
+ };
+
+ // REACT-NATIVE-WEB patch to preserve during future RN merges: Support inverted wheel scroller.
+@@ -748,6 +757,26 @@ class VirtualizedList extends StateSafePureComponent {
+ }
+ }
+ }
++ static _findItemIndexWithKey(props, key, hint) {
++ var itemCount = props.getItemCount(props.data);
++ if (hint != null && hint >= 0 && hint < itemCount) {
++ var curKey = VirtualizedList._getItemKey(props, hint);
++ if (curKey === key) {
++ return hint;
++ }
++ }
++ for (var ii = 0; ii < itemCount; ii++) {
++ var _curKey = VirtualizedList._getItemKey(props, ii);
++ if (_curKey === key) {
++ return ii;
++ }
+ }
++ return null;
+ }
-+
- // scrollToEnd may be janky without getItemLayout prop
- scrollToEnd(params) {
- var animated = params ? params.animated : true;
-@@ -350,6 +358,7 @@ class VirtualizedList extends StateSafePureComponent {
- };
- this._defaultRenderScrollComponent = props => {
- var onRefresh = props.onRefresh;
-+ var inversionStyle = this.props.inverted ? this.props.horizontal ? styles.rowReverse : styles.columnReverse : null;
- if (this._isNestedWithSameOrientation()) {
- // $FlowFixMe[prop-missing] - Typing ReactNativeComponent revealed errors
- return /*#__PURE__*/React.createElement(View, props);
-@@ -367,13 +376,16 @@ class VirtualizedList extends StateSafePureComponent {
- refreshing: props.refreshing,
- onRefresh: onRefresh,
- progressViewOffset: props.progressViewOffset
-- }) : props.refreshControl
-+ }) : props.refreshControl,
-+ contentContainerStyle: [inversionStyle, this.props.contentContainerStyle]
- }))
- );
- } else {
- // $FlowFixMe[prop-missing] Invalid prop usage
- // $FlowFixMe[incompatible-use]
-- return /*#__PURE__*/React.createElement(ScrollView, props);
-+ return /*#__PURE__*/React.createElement(ScrollView, _extends({}, props, {
-+ contentContainerStyle: [inversionStyle, this.props.contentContainerStyle]
-+ }));
++ static _getItemKey(props, index) {
++ var item = props.getItem(props.data, index);
++ return VirtualizedList._keyExtractor(item, index, props);
++ }
+ static _createRenderMask(props, cellsAroundViewport, additionalRegions) {
+ var itemCount = props.getItemCount(props.data);
+ invariant(cellsAroundViewport.first >= 0 && cellsAroundViewport.last >= cellsAroundViewport.first - 1 && cellsAroundViewport.last < itemCount, "Invalid cells around viewport \"[" + cellsAroundViewport.first + ", " + cellsAroundViewport.last + "]\" was passed to VirtualizedList._createRenderMask");
+@@ -796,7 +825,7 @@ class VirtualizedList extends StateSafePureComponent {
+ }
+ }
+ }
+- _adjustCellsAroundViewport(props, cellsAroundViewport) {
++ _adjustCellsAroundViewport(props, cellsAroundViewport, pendingScrollUpdateCount) {
+ var data = props.data,
+ getItemCount = props.getItemCount;
+ var onEndReachedThreshold = onEndReachedThresholdOrDefault(props.onEndReachedThreshold);
+@@ -819,17 +848,9 @@ class VirtualizedList extends StateSafePureComponent {
+ last: Math.min(cellsAroundViewport.last + renderAhead, getItemCount(data) - 1)
+ };
+ } else {
+- // If we have a non-zero initialScrollIndex and run this before we've scrolled,
+- // we'll wipe out the initialNumToRender rendered elements starting at initialScrollIndex.
+- // So let's wait until we've scrolled the view to the right place. And until then,
+- // we will trust the initialScrollIndex suggestion.
+-
+- // Thus, we want to recalculate the windowed render limits if any of the following hold:
+- // - initialScrollIndex is undefined or is 0
+- // - initialScrollIndex > 0 AND scrolling is complete
+- // - initialScrollIndex > 0 AND the end of the list is visible (this handles the case
+- // where the list is shorter than the visible area)
+- if (props.initialScrollIndex && !this._scrollMetrics.offset && Math.abs(distanceFromEnd) >= Number.EPSILON) {
++ // If we have a pending scroll update, we should not adjust the render window as it
++ // might override the correct window.
++ if (pendingScrollUpdateCount > 0) {
+ return cellsAroundViewport.last >= getItemCount(data) ? VirtualizedList._constrainToItemCount(cellsAroundViewport, props) : cellsAroundViewport;
}
+ newCellsAroundViewport = computeWindowedRenderLimits(props, maxToRenderPerBatchOrDefault(props.maxToRenderPerBatch), windowSizeOrDefault(props.windowSize), cellsAroundViewport, this.__getFrameMetricsApprox, this._scrollMetrics);
+@@ -902,16 +923,36 @@ class VirtualizedList extends StateSafePureComponent {
+ }
+ }
+ static getDerivedStateFromProps(newProps, prevState) {
++ var _newProps$maintainVis, _newProps$maintainVis2;
+ // first and last could be stale (e.g. if a new, shorter items props is passed in), so we make
+ // sure we're rendering a reasonable range here.
+ var itemCount = newProps.getItemCount(newProps.data);
+ if (itemCount === prevState.renderMask.numCells()) {
+ return prevState;
+ }
+- var constrainedCells = VirtualizedList._constrainToItemCount(prevState.cellsAroundViewport, newProps);
++ var maintainVisibleContentPositionAdjustment = null;
++ var prevFirstVisibleItemKey = prevState.firstVisibleItemKey;
++ var minIndexForVisible = (_newProps$maintainVis = (_newProps$maintainVis2 = newProps.maintainVisibleContentPosition) == null ? void 0 : _newProps$maintainVis2.minIndexForVisible) !== null && _newProps$maintainVis !== void 0 ? _newProps$maintainVis : 0;
++ var newFirstVisibleItemKey = newProps.getItemCount(newProps.data) > minIndexForVisible ? VirtualizedList._getItemKey(newProps, minIndexForVisible) : null;
++ if (newProps.maintainVisibleContentPosition != null && prevFirstVisibleItemKey != null && newFirstVisibleItemKey != null) {
++ if (newFirstVisibleItemKey !== prevFirstVisibleItemKey) {
++ // Fast path if items were added at the start of the list.
++ var hint = itemCount - prevState.renderMask.numCells() + minIndexForVisible;
++ var firstVisibleItemIndex = VirtualizedList._findItemIndexWithKey(newProps, prevFirstVisibleItemKey, hint);
++ maintainVisibleContentPositionAdjustment = firstVisibleItemIndex != null ? firstVisibleItemIndex - minIndexForVisible : null;
++ } else {
++ maintainVisibleContentPositionAdjustment = null;
++ }
++ }
++ var constrainedCells = VirtualizedList._constrainToItemCount(maintainVisibleContentPositionAdjustment != null ? {
++ first: prevState.cellsAroundViewport.first + maintainVisibleContentPositionAdjustment,
++ last: prevState.cellsAroundViewport.last + maintainVisibleContentPositionAdjustment
++ } : prevState.cellsAroundViewport, newProps);
+ return {
+ cellsAroundViewport: constrainedCells,
+- renderMask: VirtualizedList._createRenderMask(newProps, constrainedCells)
++ renderMask: VirtualizedList._createRenderMask(newProps, constrainedCells),
++ firstVisibleItemKey: newFirstVisibleItemKey,
++ pendingScrollUpdateCount: maintainVisibleContentPositionAdjustment != null ? prevState.pendingScrollUpdateCount + 1 : prevState.pendingScrollUpdateCount
};
- this._onCellLayout = (e, cellKey, index) => {
-@@ -683,7 +695,7 @@ class VirtualizedList extends StateSafePureComponent {
- onViewableItemsChanged = _this$props3.onViewableItemsChanged,
- viewabilityConfig = _this$props3.viewabilityConfig;
- if (onViewableItemsChanged) {
-- this._viewabilityTuples.push({
-+ this.pushOrUnshift(this._viewabilityTuples, {
- viewabilityHelper: new ViewabilityHelper(viewabilityConfig),
- onViewableItemsChanged: onViewableItemsChanged
- });
-@@ -937,10 +949,10 @@ class VirtualizedList extends StateSafePureComponent {
- var key = _this._keyExtractor(item, ii, _this.props);
+ }
+ _pushCells(cells, stickyHeaderIndices, stickyIndicesFromProps, first, last, inversionStyle) {
+@@ -934,7 +975,7 @@ class VirtualizedList extends StateSafePureComponent {
+ last = Math.min(end, last);
+ var _loop = function _loop() {
+ var item = getItem(data, ii);
+- var key = _this._keyExtractor(item, ii, _this.props);
++ var key = VirtualizedList._keyExtractor(item, ii, _this.props);
_this._indicesToKeys.set(ii, key);
if (stickyIndicesFromProps.has(ii + stickyOffset)) {
-- stickyHeaderIndices.push(cells.length);
-+ _this.pushOrUnshift(stickyHeaderIndices, cells.length);
- }
- var shouldListenForLayout = getItemLayout == null || debug || _this._fillRateHelper.enabled();
-- cells.push( /*#__PURE__*/React.createElement(CellRenderer, _extends({
-+ _this.pushOrUnshift(cells, /*#__PURE__*/React.createElement(CellRenderer, _extends({
- CellRendererComponent: CellRendererComponent,
- ItemSeparatorComponent: ii < end ? ItemSeparatorComponent : undefined,
- ListItemComponent: ListItemComponent,
-@@ -1012,14 +1024,14 @@ class VirtualizedList extends StateSafePureComponent {
- // 1. Add cell for ListHeaderComponent
- if (ListHeaderComponent) {
- if (stickyIndicesFromProps.has(0)) {
-- stickyHeaderIndices.push(0);
-+ this.pushOrUnshift(stickyHeaderIndices, 0);
- }
- var _element = /*#__PURE__*/React.isValidElement(ListHeaderComponent) ? ListHeaderComponent :
- /*#__PURE__*/
- // $FlowFixMe[not-a-component]
- // $FlowFixMe[incompatible-type-arg]
- React.createElement(ListHeaderComponent, null);
-- cells.push( /*#__PURE__*/React.createElement(VirtualizedListCellContextProvider, {
-+ this.pushOrUnshift(cells, /*#__PURE__*/React.createElement(VirtualizedListCellContextProvider, {
+ stickyHeaderIndices.push(cells.length);
+@@ -969,20 +1010,23 @@ class VirtualizedList extends StateSafePureComponent {
+ }
+ static _constrainToItemCount(cells, props) {
+ var itemCount = props.getItemCount(props.data);
+- var last = Math.min(itemCount - 1, cells.last);
++ var lastPossibleCellIndex = itemCount - 1;
++
++ // Constraining `last` may significantly shrink the window. Adjust `first`
++ // to expand the window if the new `last` results in a new window smaller
++ // than the number of cells rendered per batch.
+ var maxToRenderPerBatch = maxToRenderPerBatchOrDefault(props.maxToRenderPerBatch);
++ var maxFirst = Math.max(0, lastPossibleCellIndex - maxToRenderPerBatch);
+ return {
+- first: clamp(0, itemCount - 1 - maxToRenderPerBatch, cells.first),
+- last
++ first: clamp(0, cells.first, maxFirst),
++ last: Math.min(lastPossibleCellIndex, cells.last)
+ };
+ }
+ _isNestedWithSameOrientation() {
+ var nestedContext = this.context;
+ return !!(nestedContext && !!nestedContext.horizontal === horizontalOrDefault(this.props.horizontal));
+ }
+- _keyExtractor(item, index, props
+- // $FlowFixMe[missing-local-annot]
+- ) {
++ static _keyExtractor(item, index, props) {
+ if (props.keyExtractor != null) {
+ return props.keyExtractor(item, index);
+ }
+@@ -1022,7 +1066,12 @@ class VirtualizedList extends StateSafePureComponent {
+ cells.push( /*#__PURE__*/React.createElement(VirtualizedListCellContextProvider, {
cellKey: this._getCellKey() + '-header',
key: "$header"
- }, /*#__PURE__*/React.createElement(View, {
-@@ -1038,7 +1050,7 @@ class VirtualizedList extends StateSafePureComponent {
- // $FlowFixMe[not-a-component]
- // $FlowFixMe[incompatible-type-arg]
- React.createElement(ListEmptyComponent, null);
-- cells.push( /*#__PURE__*/React.createElement(VirtualizedListCellContextProvider, {
-+ this.pushOrUnshift(cells, /*#__PURE__*/React.createElement(VirtualizedListCellContextProvider, {
- cellKey: this._getCellKey() + '-empty',
- key: "$empty"
- }, /*#__PURE__*/React.cloneElement(_element2, {
-@@ -1077,7 +1089,7 @@ class VirtualizedList extends StateSafePureComponent {
- var firstMetrics = this.__getFrameMetricsApprox(section.first, this.props);
- var lastMetrics = this.__getFrameMetricsApprox(last, this.props);
- var spacerSize = lastMetrics.offset + lastMetrics.length - firstMetrics.offset;
-- cells.push( /*#__PURE__*/React.createElement(View, {
-+ this.pushOrUnshift(cells, /*#__PURE__*/React.createElement(View, {
- key: "$spacer-" + section.first,
- style: {
- [spacerKey]: spacerSize
-@@ -1100,7 +1112,7 @@ class VirtualizedList extends StateSafePureComponent {
- // $FlowFixMe[not-a-component]
- // $FlowFixMe[incompatible-type-arg]
- React.createElement(ListFooterComponent, null);
-- cells.push( /*#__PURE__*/React.createElement(VirtualizedListCellContextProvider, {
-+ this.pushOrUnshift(cells, /*#__PURE__*/React.createElement(VirtualizedListCellContextProvider, {
- cellKey: this._getFooterCellKey(),
- key: "$footer"
- }, /*#__PURE__*/React.createElement(View, {
-@@ -1266,7 +1278,7 @@ class VirtualizedList extends StateSafePureComponent {
- * suppresses an error found when Flow v0.68 was deployed. To see the
- * error delete this comment and run Flow. */
- if (frame.inLayout) {
-- framesInLayout.push(frame);
-+ this.pushOrUnshift(framesInLayout, frame);
- }
+- }, /*#__PURE__*/React.createElement(View, {
++ }, /*#__PURE__*/React.createElement(View
++ // We expect that header component will be a single native view so make it
++ // not collapsable to avoid this view being flattened and make this assumption
++ // no longer true.
++ , {
++ collapsable: false,
+ onLayout: this._onLayoutHeader,
+ style: [inversionStyle, this.props.ListHeaderComponentStyle]
+ },
+@@ -1124,7 +1173,11 @@ class VirtualizedList extends StateSafePureComponent {
+ // TODO: Android support
+ invertStickyHeaders: this.props.invertStickyHeaders !== undefined ? this.props.invertStickyHeaders : this.props.inverted,
+ stickyHeaderIndices,
+- style: inversionStyle ? [inversionStyle, this.props.style] : this.props.style
++ style: inversionStyle ? [inversionStyle, this.props.style] : this.props.style,
++ maintainVisibleContentPosition: this.props.maintainVisibleContentPosition != null ? _objectSpread(_objectSpread({}, this.props.maintainVisibleContentPosition), {}, {
++ // Adjust index to account for ListHeaderComponent.
++ minIndexForVisible: this.props.maintainVisibleContentPosition.minIndexForVisible + (this.props.ListHeaderComponent ? 1 : 0)
++ }) : undefined
+ });
+ this._hasMore = this.state.cellsAroundViewport.last < itemCount - 1;
+ var innerRet = /*#__PURE__*/React.createElement(VirtualizedListContextProvider, {
+@@ -1307,8 +1360,12 @@ class VirtualizedList extends StateSafePureComponent {
+ onStartReached = _this$props8.onStartReached,
+ onStartReachedThreshold = _this$props8.onStartReachedThreshold,
+ onEndReached = _this$props8.onEndReached,
+- onEndReachedThreshold = _this$props8.onEndReachedThreshold,
+- initialScrollIndex = _this$props8.initialScrollIndex;
++ onEndReachedThreshold = _this$props8.onEndReachedThreshold;
++ // If we have any pending scroll updates it means that the scroll metrics
++ // are out of date and we should not call any of the edge reached callbacks.
++ if (this.state.pendingScrollUpdateCount > 0) {
++ return;
++ }
+ var _this$_scrollMetrics2 = this._scrollMetrics,
+ contentLength = _this$_scrollMetrics2.contentLength,
+ visibleLength = _this$_scrollMetrics2.visibleLength,
+@@ -1348,16 +1405,10 @@ class VirtualizedList extends StateSafePureComponent {
+ // and call onStartReached only once for a given content length,
+ // and only if onEndReached is not being executed
+ else if (onStartReached != null && this.state.cellsAroundViewport.first === 0 && isWithinStartThreshold && this._scrollMetrics.contentLength !== this._sentStartForContentLength) {
+- // On initial mount when using initialScrollIndex the offset will be 0 initially
+- // and will trigger an unexpected onStartReached. To avoid this we can use
+- // timestamp to differentiate between the initial scroll metrics and when we actually
+- // received the first scroll event.
+- if (!initialScrollIndex || this._scrollMetrics.timestamp !== 0) {
+- this._sentStartForContentLength = this._scrollMetrics.contentLength;
+- onStartReached({
+- distanceFromStart
+- });
+- }
++ this._sentStartForContentLength = this._scrollMetrics.contentLength;
++ onStartReached({
++ distanceFromStart
++ });
+ }
+
+ // If the user scrolls away from the start or end and back again,
+@@ -1412,6 +1463,11 @@ class VirtualizedList extends StateSafePureComponent {
}
- var windowTop = this.__getFrameMetricsApprox(this.state.cellsAroundViewport.first, this.props).offset;
-@@ -1452,6 +1464,12 @@ var styles = StyleSheet.create({
- left: 0,
- borderColor: 'red',
- borderWidth: 2
-+ },
-+ rowReverse: {
-+ flexDirection: 'row-reverse'
-+ },
-+ columnReverse: {
-+ flexDirection: 'column-reverse'
}
- });
- export default VirtualizedList;
-\ No newline at end of file
+ _updateViewableItems(props, cellsAroundViewport) {
++ // If we have any pending scroll updates it means that the scroll metrics
++ // are out of date and we should not call any of the visibility callbacks.
++ if (this.state.pendingScrollUpdateCount > 0) {
++ return;
++ }
+ this._viewabilityTuples.forEach(tuple => {
+ tuple.viewabilityHelper.onUpdate(props, this._scrollMetrics.offset, this._scrollMetrics.visibleLength, this._getFrameMetrics, this._createViewToken, tuple.onViewableItemsChanged, cellsAroundViewport);
+ });
diff --git a/node_modules/react-native-web/src/vendor/react-native/VirtualizedList/index.js b/node_modules/react-native-web/src/vendor/react-native/VirtualizedList/index.js
-index c7d68bb..46b3fc9 100644
+index c7d68bb..43f9653 100644
--- a/node_modules/react-native-web/src/vendor/react-native/VirtualizedList/index.js
+++ b/node_modules/react-native-web/src/vendor/react-native/VirtualizedList/index.js
-@@ -167,6 +167,14 @@ function findLastWhere(
- class VirtualizedList extends StateSafePureComponent {
- static contextType: typeof VirtualizedListContext = VirtualizedListContext;
+@@ -75,6 +75,10 @@ type ViewabilityHelperCallbackTuple = {
+ type State = {
+ renderMask: CellRenderMask,
+ cellsAroundViewport: {first: number, last: number},
++ // Used to track items added at the start of the list for maintainVisibleContentPosition.
++ firstVisibleItemKey: ?string,
++ // When > 0 the scroll position available in JS is considered stale and should not be used.
++ pendingScrollUpdateCount: number,
+ };
+
+ /**
+@@ -447,9 +451,24 @@ class VirtualizedList extends StateSafePureComponent {
+
+ const initialRenderRegion = VirtualizedList._initialRenderRegion(props);
-+ pushOrUnshift(input: Array, item: Item) {
-+ if (this.props.inverted) {
-+ input.unshift(item)
-+ } else {
-+ input.push(item)
++ const minIndexForVisible =
++ this.props.maintainVisibleContentPosition?.minIndexForVisible ?? 0;
++
+ this.state = {
+ cellsAroundViewport: initialRenderRegion,
+ renderMask: VirtualizedList._createRenderMask(props, initialRenderRegion),
++ firstVisibleItemKey:
++ this.props.getItemCount(this.props.data) > minIndexForVisible
++ ? VirtualizedList._getItemKey(this.props, minIndexForVisible)
++ : null,
++ // When we have a non-zero initialScrollIndex, we will receive a
++ // scroll event later so this will prevent the window from updating
++ // until we get a valid offset.
++ pendingScrollUpdateCount:
++ this.props.initialScrollIndex != null &&
++ this.props.initialScrollIndex > 0
++ ? 1
++ : 0,
+ };
+
+ // REACT-NATIVE-WEB patch to preserve during future RN merges: Support inverted wheel scroller.
+@@ -534,6 +553,40 @@ class VirtualizedList extends StateSafePureComponent {
+ }
+ }
+
++ static _findItemIndexWithKey(
++ props: Props,
++ key: string,
++ hint: ?number,
++ ): ?number {
++ const itemCount = props.getItemCount(props.data);
++ if (hint != null && hint >= 0 && hint < itemCount) {
++ const curKey = VirtualizedList._getItemKey(props, hint);
++ if (curKey === key) {
++ return hint;
++ }
+ }
++ for (let ii = 0; ii < itemCount; ii++) {
++ const curKey = VirtualizedList._getItemKey(props, ii);
++ if (curKey === key) {
++ return ii;
++ }
++ }
++ return null;
++ }
++
++ static _getItemKey(
++ props: {
++ data: Props['data'],
++ getItem: Props['getItem'],
++ keyExtractor: Props['keyExtractor'],
++ ...
++ },
++ index: number,
++ ): string {
++ const item = props.getItem(props.data, index);
++ return VirtualizedList._keyExtractor(item, index, props);
+ }
+
- // scrollToEnd may be janky without getItemLayout prop
- scrollToEnd(params?: ?{animated?: ?boolean, ...}) {
- const animated = params ? params.animated : true;
-@@ -438,7 +446,7 @@ class VirtualizedList extends StateSafePureComponent {
+ static _createRenderMask(
+ props: Props,
+ cellsAroundViewport: {first: number, last: number},
+@@ -617,6 +670,7 @@ class VirtualizedList extends StateSafePureComponent {
+ _adjustCellsAroundViewport(
+ props: Props,
+ cellsAroundViewport: {first: number, last: number},
++ pendingScrollUpdateCount: number,
+ ): {first: number, last: number} {
+ const {data, getItemCount} = props;
+ const onEndReachedThreshold = onEndReachedThresholdOrDefault(
+@@ -648,21 +702,9 @@ class VirtualizedList extends StateSafePureComponent {
+ ),
+ };
} else {
- const {onViewableItemsChanged, viewabilityConfig} = this.props;
- if (onViewableItemsChanged) {
-- this._viewabilityTuples.push({
-+ this.pushOrUnshift(this._viewabilityTuples, {
- viewabilityHelper: new ViewabilityHelper(viewabilityConfig),
- onViewableItemsChanged: onViewableItemsChanged,
- });
-@@ -814,13 +822,13 @@ class VirtualizedList extends StateSafePureComponent {
+- // If we have a non-zero initialScrollIndex and run this before we've scrolled,
+- // we'll wipe out the initialNumToRender rendered elements starting at initialScrollIndex.
+- // So let's wait until we've scrolled the view to the right place. And until then,
+- // we will trust the initialScrollIndex suggestion.
+-
+- // Thus, we want to recalculate the windowed render limits if any of the following hold:
+- // - initialScrollIndex is undefined or is 0
+- // - initialScrollIndex > 0 AND scrolling is complete
+- // - initialScrollIndex > 0 AND the end of the list is visible (this handles the case
+- // where the list is shorter than the visible area)
+- if (
+- props.initialScrollIndex &&
+- !this._scrollMetrics.offset &&
+- Math.abs(distanceFromEnd) >= Number.EPSILON
+- ) {
++ // If we have a pending scroll update, we should not adjust the render window as it
++ // might override the correct window.
++ if (pendingScrollUpdateCount > 0) {
+ return cellsAroundViewport.last >= getItemCount(data)
+ ? VirtualizedList._constrainToItemCount(cellsAroundViewport, props)
+ : cellsAroundViewport;
+@@ -771,14 +813,59 @@ class VirtualizedList extends StateSafePureComponent {
+ return prevState;
+ }
+
++ let maintainVisibleContentPositionAdjustment: ?number = null;
++ const prevFirstVisibleItemKey = prevState.firstVisibleItemKey;
++ const minIndexForVisible =
++ newProps.maintainVisibleContentPosition?.minIndexForVisible ?? 0;
++ const newFirstVisibleItemKey =
++ newProps.getItemCount(newProps.data) > minIndexForVisible
++ ? VirtualizedList._getItemKey(newProps, minIndexForVisible)
++ : null;
++ if (
++ newProps.maintainVisibleContentPosition != null &&
++ prevFirstVisibleItemKey != null &&
++ newFirstVisibleItemKey != null
++ ) {
++ if (newFirstVisibleItemKey !== prevFirstVisibleItemKey) {
++ // Fast path if items were added at the start of the list.
++ const hint =
++ itemCount - prevState.renderMask.numCells() + minIndexForVisible;
++ const firstVisibleItemIndex = VirtualizedList._findItemIndexWithKey(
++ newProps,
++ prevFirstVisibleItemKey,
++ hint,
++ );
++ maintainVisibleContentPositionAdjustment =
++ firstVisibleItemIndex != null
++ ? firstVisibleItemIndex - minIndexForVisible
++ : null;
++ } else {
++ maintainVisibleContentPositionAdjustment = null;
++ }
++ }
++
+ const constrainedCells = VirtualizedList._constrainToItemCount(
+- prevState.cellsAroundViewport,
++ maintainVisibleContentPositionAdjustment != null
++ ? {
++ first:
++ prevState.cellsAroundViewport.first +
++ maintainVisibleContentPositionAdjustment,
++ last:
++ prevState.cellsAroundViewport.last +
++ maintainVisibleContentPositionAdjustment,
++ }
++ : prevState.cellsAroundViewport,
+ newProps,
+ );
+
+ return {
+ cellsAroundViewport: constrainedCells,
+ renderMask: VirtualizedList._createRenderMask(newProps, constrainedCells),
++ firstVisibleItemKey: newFirstVisibleItemKey,
++ pendingScrollUpdateCount:
++ maintainVisibleContentPositionAdjustment != null
++ ? prevState.pendingScrollUpdateCount + 1
++ : prevState.pendingScrollUpdateCount,
+ };
+ }
+
+@@ -810,7 +897,7 @@ class VirtualizedList extends StateSafePureComponent {
+
+ for (let ii = first; ii <= last; ii++) {
+ const item = getItem(data, ii);
+- const key = this._keyExtractor(item, ii, this.props);
++ const key = VirtualizedList._keyExtractor(item, ii, this.props);
this._indicesToKeys.set(ii, key);
if (stickyIndicesFromProps.has(ii + stickyOffset)) {
-- stickyHeaderIndices.push(cells.length);
-+ this.pushOrUnshift(stickyHeaderIndices, (cells.length));
- }
+@@ -853,15 +940,19 @@ class VirtualizedList extends StateSafePureComponent {
+ props: Props,
+ ): {first: number, last: number} {
+ const itemCount = props.getItemCount(props.data);
+- const last = Math.min(itemCount - 1, cells.last);
++ const lastPossibleCellIndex = itemCount - 1;
- const shouldListenForLayout =
- getItemLayout == null || debug || this._fillRateHelper.enabled();
++ // Constraining `last` may significantly shrink the window. Adjust `first`
++ // to expand the window if the new `last` results in a new window smaller
++ // than the number of cells rendered per batch.
+ const maxToRenderPerBatch = maxToRenderPerBatchOrDefault(
+ props.maxToRenderPerBatch,
+ );
++ const maxFirst = Math.max(0, lastPossibleCellIndex - maxToRenderPerBatch);
-- cells.push(
-+ this.pushOrUnshift(cells,
- {
- // 1. Add cell for ListHeaderComponent
- if (ListHeaderComponent) {
- if (stickyIndicesFromProps.has(0)) {
-- stickyHeaderIndices.push(0);
-+ this.pushOrUnshift(stickyHeaderIndices, 0);
- }
- const element = React.isValidElement(ListHeaderComponent) ? (
- ListHeaderComponent
-@@ -932,7 +940,7 @@ class VirtualizedList extends StateSafePureComponent {
- // $FlowFixMe[incompatible-type-arg]
-
- );
-- cells.push(
-+ this.pushOrUnshift(cells,
- {
+ _getSpacerKey = (isVertical: boolean): string =>
+ isVertical ? 'height' : 'width';
+
+- _keyExtractor(
++ static _keyExtractor(
+ item: Item,
+ index: number,
+ props: {
+ keyExtractor?: ?(item: Item, index: number) => string,
+ ...
+ },
+- // $FlowFixMe[missing-local-annot]
+- ) {
++ ): string {
+ if (props.keyExtractor != null) {
+ return props.keyExtractor(item, index);
+ }
+@@ -937,6 +1027,10 @@ class VirtualizedList extends StateSafePureComponent {
cellKey={this._getCellKey() + '-header'}
key="$header">
-@@ -963,7 +971,7 @@ class VirtualizedList extends StateSafePureComponent {
- // $FlowFixMe[incompatible-type-arg]
-
- )): any);
-- cells.push(
-+ this.pushOrUnshift(cells,
-
-@@ -1017,7 +1025,7 @@ class VirtualizedList extends StateSafePureComponent {
- const lastMetrics = this.__getFrameMetricsApprox(last, this.props);
- const spacerSize =
- lastMetrics.offset + lastMetrics.length - firstMetrics.offset;
-- cells.push(
-+ this.pushOrUnshift(cells,
- {
- // $FlowFixMe[incompatible-type-arg]
-
- );
-- cells.push(
-+ this.pushOrUnshift(cells,
-
-@@ -1246,6 +1254,12 @@ class VirtualizedList extends StateSafePureComponent {
- * LTI update could not be added via codemod */
- _defaultRenderScrollComponent = props => {
- const onRefresh = props.onRefresh;
-+ const inversionStyle = this.props.inverted
-+ ? this.props.horizontal
-+ ? styles.rowReverse
-+ : styles.columnReverse
-+ : null;
-+
- if (this._isNestedWithSameOrientation()) {
- // $FlowFixMe[prop-missing] - Typing ReactNativeComponent revealed errors
- return ;
-@@ -1273,12 +1287,24 @@ class VirtualizedList extends StateSafePureComponent {
- props.refreshControl
- )
- }
-+ contentContainerStyle={[
-+ inversionStyle,
-+ this.props.contentContainerStyle,
-+ ]}
- />
- );
- } else {
- // $FlowFixMe[prop-missing] Invalid prop usage
- // $FlowFixMe[incompatible-use]
-- return ;
-+ return (
-+
-+ );
- }
- };
+ {
+ style: inversionStyle
+ ? [inversionStyle, this.props.style]
+ : this.props.style,
++ maintainVisibleContentPosition:
++ this.props.maintainVisibleContentPosition != null
++ ? {
++ ...this.props.maintainVisibleContentPosition,
++ // Adjust index to account for ListHeaderComponent.
++ minIndexForVisible:
++ this.props.maintainVisibleContentPosition.minIndexForVisible +
++ (this.props.ListHeaderComponent ? 1 : 0),
++ }
++ : undefined,
+ };
-@@ -1432,7 +1458,7 @@ class VirtualizedList extends StateSafePureComponent {
- * suppresses an error found when Flow v0.68 was deployed. To see the
- * error delete this comment and run Flow. */
- if (frame.inLayout) {
-- framesInLayout.push(frame);
-+ this.pushOrUnshift(framesInLayout, frame);
- }
+ this._hasMore = this.state.cellsAroundViewport.last < itemCount - 1;
+@@ -1516,8 +1620,12 @@ class VirtualizedList extends StateSafePureComponent {
+ onStartReachedThreshold,
+ onEndReached,
+ onEndReachedThreshold,
+- initialScrollIndex,
+ } = this.props;
++ // If we have any pending scroll updates it means that the scroll metrics
++ // are out of date and we should not call any of the edge reached callbacks.
++ if (this.state.pendingScrollUpdateCount > 0) {
++ return;
++ }
+ const {contentLength, visibleLength, offset} = this._scrollMetrics;
+ let distanceFromStart = offset;
+ let distanceFromEnd = contentLength - visibleLength - offset;
+@@ -1569,14 +1677,8 @@ class VirtualizedList extends StateSafePureComponent {
+ isWithinStartThreshold &&
+ this._scrollMetrics.contentLength !== this._sentStartForContentLength
+ ) {
+- // On initial mount when using initialScrollIndex the offset will be 0 initially
+- // and will trigger an unexpected onStartReached. To avoid this we can use
+- // timestamp to differentiate between the initial scroll metrics and when we actually
+- // received the first scroll event.
+- if (!initialScrollIndex || this._scrollMetrics.timestamp !== 0) {
+- this._sentStartForContentLength = this._scrollMetrics.contentLength;
+- onStartReached({distanceFromStart});
+- }
++ this._sentStartForContentLength = this._scrollMetrics.contentLength;
++ onStartReached({distanceFromStart});
}
- const windowTop = this.__getFrameMetricsApprox(
-@@ -2044,6 +2070,12 @@ const styles = StyleSheet.create({
- borderColor: 'red',
- borderWidth: 2,
- },
-+ rowReverse: {
-+ flexDirection: 'row-reverse',
-+ },
-+ columnReverse: {
-+ flexDirection: 'column-reverse',
-+ },
- });
- export default VirtualizedList;
-\ No newline at end of file
+ // If the user scrolls away from the start or end and back again,
+@@ -1703,6 +1805,11 @@ class VirtualizedList extends StateSafePureComponent {
+ visibleLength,
+ zoomScale,
+ };
++ if (this.state.pendingScrollUpdateCount > 0) {
++ this.setState(state => ({
++ pendingScrollUpdateCount: state.pendingScrollUpdateCount - 1,
++ }));
++ }
+ this._updateViewableItems(this.props, this.state.cellsAroundViewport);
+ if (!this.props) {
+ return;
+@@ -1818,6 +1925,7 @@ class VirtualizedList extends StateSafePureComponent {
+ const cellsAroundViewport = this._adjustCellsAroundViewport(
+ props,
+ state.cellsAroundViewport,
++ state.pendingScrollUpdateCount,
+ );
+ const renderMask = VirtualizedList._createRenderMask(
+ props,
+@@ -1848,7 +1956,7 @@ class VirtualizedList extends StateSafePureComponent {
+ return {
+ index,
+ item,
+- key: this._keyExtractor(item, index, props),
++ key: VirtualizedList._keyExtractor(item, index, props),
+ isViewable,
+ };
+ };
+@@ -1909,13 +2017,12 @@ class VirtualizedList extends StateSafePureComponent {
+ inLayout?: boolean,
+ ...
+ } => {
+- const {data, getItem, getItemCount, getItemLayout} = props;
++ const {data, getItemCount, getItemLayout} = props;
+ invariant(
+ index >= 0 && index < getItemCount(data),
+ 'Tried to get frame for out of range index ' + index,
+ );
+- const item = getItem(data, index);
+- const frame = this._frames[this._keyExtractor(item, index, props)];
++ const frame = this._frames[VirtualizedList._getItemKey(props, index)];
+ if (!frame || frame.index !== index) {
+ if (getItemLayout) {
+ /* $FlowFixMe[prop-missing] (>=0.63.0 site=react_native_fb) This comment
+@@ -1950,11 +2057,8 @@ class VirtualizedList extends StateSafePureComponent {
+ // where it is.
+ if (
+ focusedCellIndex >= itemCount ||
+- this._keyExtractor(
+- props.getItem(props.data, focusedCellIndex),
+- focusedCellIndex,
+- props,
+- ) !== this._lastFocusedCellKey
++ VirtualizedList._getItemKey(props, focusedCellIndex) !==
++ this._lastFocusedCellKey
+ ) {
+ return [];
+ }
+@@ -1995,6 +2099,11 @@ class VirtualizedList extends StateSafePureComponent {
+ props: FrameMetricProps,
+ cellsAroundViewport: {first: number, last: number},
+ ) {
++ // If we have any pending scroll updates it means that the scroll metrics
++ // are out of date and we should not call any of the visibility callbacks.
++ if (this.state.pendingScrollUpdateCount > 0) {
++ return;
++ }
+ this._viewabilityTuples.forEach(tuple => {
+ tuple.viewabilityHelper.onUpdate(
+ props,
diff --git a/patches/react-native-web+0.19.9+002+fix-mvcp.patch b/patches/react-native-web+0.19.9+002+fix-mvcp.patch
deleted file mode 100644
index afd681bba3b0..000000000000
--- a/patches/react-native-web+0.19.9+002+fix-mvcp.patch
+++ /dev/null
@@ -1,687 +0,0 @@
-diff --git a/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js b/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js
-index a6fe142..faeb323 100644
---- a/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js
-+++ b/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js
-@@ -293,7 +293,7 @@ class VirtualizedList extends StateSafePureComponent {
- // $FlowFixMe[missing-local-annot]
-
- constructor(_props) {
-- var _this$props$updateCel;
-+ var _this$props$updateCel, _this$props$maintainV, _this$props$maintainV2;
- super(_props);
- this._getScrollMetrics = () => {
- return this._scrollMetrics;
-@@ -532,6 +532,11 @@ class VirtualizedList extends StateSafePureComponent {
- visibleLength,
- zoomScale
- };
-+ if (this.state.pendingScrollUpdateCount > 0) {
-+ this.setState(state => ({
-+ pendingScrollUpdateCount: state.pendingScrollUpdateCount - 1
-+ }));
-+ }
- this._updateViewableItems(this.props, this.state.cellsAroundViewport);
- if (!this.props) {
- return;
-@@ -581,7 +586,7 @@ class VirtualizedList extends StateSafePureComponent {
- this._updateCellsToRender = () => {
- this._updateViewableItems(this.props, this.state.cellsAroundViewport);
- this.setState((state, props) => {
-- var cellsAroundViewport = this._adjustCellsAroundViewport(props, state.cellsAroundViewport);
-+ var cellsAroundViewport = this._adjustCellsAroundViewport(props, state.cellsAroundViewport, state.pendingScrollUpdateCount);
- var renderMask = VirtualizedList._createRenderMask(props, cellsAroundViewport, this._getNonViewportRenderRegions(props));
- if (cellsAroundViewport.first === state.cellsAroundViewport.first && cellsAroundViewport.last === state.cellsAroundViewport.last && renderMask.equals(state.renderMask)) {
- return null;
-@@ -601,7 +606,7 @@ class VirtualizedList extends StateSafePureComponent {
- return {
- index,
- item,
-- key: this._keyExtractor(item, index, props),
-+ key: VirtualizedList._keyExtractor(item, index, props),
- isViewable
- };
- };
-@@ -633,12 +638,10 @@ class VirtualizedList extends StateSafePureComponent {
- };
- this._getFrameMetrics = (index, props) => {
- var data = props.data,
-- getItem = props.getItem,
- getItemCount = props.getItemCount,
- getItemLayout = props.getItemLayout;
- invariant(index >= 0 && index < getItemCount(data), 'Tried to get frame for out of range index ' + index);
-- var item = getItem(data, index);
-- var frame = this._frames[this._keyExtractor(item, index, props)];
-+ var frame = this._frames[VirtualizedList._getItemKey(props, index)];
- if (!frame || frame.index !== index) {
- if (getItemLayout) {
- /* $FlowFixMe[prop-missing] (>=0.63.0 site=react_native_fb) This comment
-@@ -662,7 +665,7 @@ class VirtualizedList extends StateSafePureComponent {
-
- // The last cell we rendered may be at a new index. Bail if we don't know
- // where it is.
-- if (focusedCellIndex >= itemCount || this._keyExtractor(props.getItem(props.data, focusedCellIndex), focusedCellIndex, props) !== this._lastFocusedCellKey) {
-+ if (focusedCellIndex >= itemCount || VirtualizedList._getItemKey(props, focusedCellIndex) !== this._lastFocusedCellKey) {
- return [];
- }
- var first = focusedCellIndex;
-@@ -702,9 +705,15 @@ class VirtualizedList extends StateSafePureComponent {
- }
- }
- var initialRenderRegion = VirtualizedList._initialRenderRegion(_props);
-+ var minIndexForVisible = (_this$props$maintainV = (_this$props$maintainV2 = this.props.maintainVisibleContentPosition) == null ? void 0 : _this$props$maintainV2.minIndexForVisible) !== null && _this$props$maintainV !== void 0 ? _this$props$maintainV : 0;
- this.state = {
- cellsAroundViewport: initialRenderRegion,
-- renderMask: VirtualizedList._createRenderMask(_props, initialRenderRegion)
-+ renderMask: VirtualizedList._createRenderMask(_props, initialRenderRegion),
-+ firstVisibleItemKey: this.props.getItemCount(this.props.data) > minIndexForVisible ? VirtualizedList._getItemKey(this.props, minIndexForVisible) : null,
-+ // When we have a non-zero initialScrollIndex, we will receive a
-+ // scroll event later so this will prevent the window from updating
-+ // until we get a valid offset.
-+ pendingScrollUpdateCount: this.props.initialScrollIndex != null && this.props.initialScrollIndex > 0 ? 1 : 0
- };
-
- // REACT-NATIVE-WEB patch to preserve during future RN merges: Support inverted wheel scroller.
-@@ -715,7 +724,7 @@ class VirtualizedList extends StateSafePureComponent {
- var clientLength = this.props.horizontal ? ev.target.clientWidth : ev.target.clientHeight;
- var isEventTargetScrollable = scrollLength > clientLength;
- var delta = this.props.horizontal ? ev.deltaX || ev.wheelDeltaX : ev.deltaY || ev.wheelDeltaY;
-- var leftoverDelta = delta;
-+ var leftoverDelta = delta * 0.5;
- if (isEventTargetScrollable) {
- leftoverDelta = delta < 0 ? Math.min(delta + scrollOffset, 0) : Math.max(delta - (scrollLength - clientLength - scrollOffset), 0);
- }
-@@ -760,6 +769,26 @@ class VirtualizedList extends StateSafePureComponent {
- }
- }
- }
-+ static _findItemIndexWithKey(props, key, hint) {
-+ var itemCount = props.getItemCount(props.data);
-+ if (hint != null && hint >= 0 && hint < itemCount) {
-+ var curKey = VirtualizedList._getItemKey(props, hint);
-+ if (curKey === key) {
-+ return hint;
-+ }
-+ }
-+ for (var ii = 0; ii < itemCount; ii++) {
-+ var _curKey = VirtualizedList._getItemKey(props, ii);
-+ if (_curKey === key) {
-+ return ii;
-+ }
-+ }
-+ return null;
-+ }
-+ static _getItemKey(props, index) {
-+ var item = props.getItem(props.data, index);
-+ return VirtualizedList._keyExtractor(item, index, props);
-+ }
- static _createRenderMask(props, cellsAroundViewport, additionalRegions) {
- var itemCount = props.getItemCount(props.data);
- invariant(cellsAroundViewport.first >= 0 && cellsAroundViewport.last >= cellsAroundViewport.first - 1 && cellsAroundViewport.last < itemCount, "Invalid cells around viewport \"[" + cellsAroundViewport.first + ", " + cellsAroundViewport.last + "]\" was passed to VirtualizedList._createRenderMask");
-@@ -808,7 +837,7 @@ class VirtualizedList extends StateSafePureComponent {
- }
- }
- }
-- _adjustCellsAroundViewport(props, cellsAroundViewport) {
-+ _adjustCellsAroundViewport(props, cellsAroundViewport, pendingScrollUpdateCount) {
- var data = props.data,
- getItemCount = props.getItemCount;
- var onEndReachedThreshold = onEndReachedThresholdOrDefault(props.onEndReachedThreshold);
-@@ -831,17 +860,9 @@ class VirtualizedList extends StateSafePureComponent {
- last: Math.min(cellsAroundViewport.last + renderAhead, getItemCount(data) - 1)
- };
- } else {
-- // If we have a non-zero initialScrollIndex and run this before we've scrolled,
-- // we'll wipe out the initialNumToRender rendered elements starting at initialScrollIndex.
-- // So let's wait until we've scrolled the view to the right place. And until then,
-- // we will trust the initialScrollIndex suggestion.
--
-- // Thus, we want to recalculate the windowed render limits if any of the following hold:
-- // - initialScrollIndex is undefined or is 0
-- // - initialScrollIndex > 0 AND scrolling is complete
-- // - initialScrollIndex > 0 AND the end of the list is visible (this handles the case
-- // where the list is shorter than the visible area)
-- if (props.initialScrollIndex && !this._scrollMetrics.offset && Math.abs(distanceFromEnd) >= Number.EPSILON) {
-+ // If we have a pending scroll update, we should not adjust the render window as it
-+ // might override the correct window.
-+ if (pendingScrollUpdateCount > 0) {
- return cellsAroundViewport.last >= getItemCount(data) ? VirtualizedList._constrainToItemCount(cellsAroundViewport, props) : cellsAroundViewport;
- }
- newCellsAroundViewport = computeWindowedRenderLimits(props, maxToRenderPerBatchOrDefault(props.maxToRenderPerBatch), windowSizeOrDefault(props.windowSize), cellsAroundViewport, this.__getFrameMetricsApprox, this._scrollMetrics);
-@@ -914,16 +935,36 @@ class VirtualizedList extends StateSafePureComponent {
- }
- }
- static getDerivedStateFromProps(newProps, prevState) {
-+ var _newProps$maintainVis, _newProps$maintainVis2;
- // first and last could be stale (e.g. if a new, shorter items props is passed in), so we make
- // sure we're rendering a reasonable range here.
- var itemCount = newProps.getItemCount(newProps.data);
- if (itemCount === prevState.renderMask.numCells()) {
- return prevState;
- }
-- var constrainedCells = VirtualizedList._constrainToItemCount(prevState.cellsAroundViewport, newProps);
-+ var maintainVisibleContentPositionAdjustment = null;
-+ var prevFirstVisibleItemKey = prevState.firstVisibleItemKey;
-+ var minIndexForVisible = (_newProps$maintainVis = (_newProps$maintainVis2 = newProps.maintainVisibleContentPosition) == null ? void 0 : _newProps$maintainVis2.minIndexForVisible) !== null && _newProps$maintainVis !== void 0 ? _newProps$maintainVis : 0;
-+ var newFirstVisibleItemKey = newProps.getItemCount(newProps.data) > minIndexForVisible ? VirtualizedList._getItemKey(newProps, minIndexForVisible) : null;
-+ if (newProps.maintainVisibleContentPosition != null && prevFirstVisibleItemKey != null && newFirstVisibleItemKey != null) {
-+ if (newFirstVisibleItemKey !== prevFirstVisibleItemKey) {
-+ // Fast path if items were added at the start of the list.
-+ var hint = itemCount - prevState.renderMask.numCells() + minIndexForVisible;
-+ var firstVisibleItemIndex = VirtualizedList._findItemIndexWithKey(newProps, prevFirstVisibleItemKey, hint);
-+ maintainVisibleContentPositionAdjustment = firstVisibleItemIndex != null ? firstVisibleItemIndex - minIndexForVisible : null;
-+ } else {
-+ maintainVisibleContentPositionAdjustment = null;
-+ }
-+ }
-+ var constrainedCells = VirtualizedList._constrainToItemCount(maintainVisibleContentPositionAdjustment != null ? {
-+ first: prevState.cellsAroundViewport.first + maintainVisibleContentPositionAdjustment,
-+ last: prevState.cellsAroundViewport.last + maintainVisibleContentPositionAdjustment
-+ } : prevState.cellsAroundViewport, newProps);
- return {
- cellsAroundViewport: constrainedCells,
-- renderMask: VirtualizedList._createRenderMask(newProps, constrainedCells)
-+ renderMask: VirtualizedList._createRenderMask(newProps, constrainedCells),
-+ firstVisibleItemKey: newFirstVisibleItemKey,
-+ pendingScrollUpdateCount: maintainVisibleContentPositionAdjustment != null ? prevState.pendingScrollUpdateCount + 1 : prevState.pendingScrollUpdateCount
- };
- }
- _pushCells(cells, stickyHeaderIndices, stickyIndicesFromProps, first, last, inversionStyle) {
-@@ -946,7 +987,7 @@ class VirtualizedList extends StateSafePureComponent {
- last = Math.min(end, last);
- var _loop = function _loop() {
- var item = getItem(data, ii);
-- var key = _this._keyExtractor(item, ii, _this.props);
-+ var key = VirtualizedList._keyExtractor(item, ii, _this.props);
- _this._indicesToKeys.set(ii, key);
- if (stickyIndicesFromProps.has(ii + stickyOffset)) {
- _this.pushOrUnshift(stickyHeaderIndices, cells.length);
-@@ -981,20 +1022,23 @@ class VirtualizedList extends StateSafePureComponent {
- }
- static _constrainToItemCount(cells, props) {
- var itemCount = props.getItemCount(props.data);
-- var last = Math.min(itemCount - 1, cells.last);
-+ var lastPossibleCellIndex = itemCount - 1;
-+
-+ // Constraining `last` may significantly shrink the window. Adjust `first`
-+ // to expand the window if the new `last` results in a new window smaller
-+ // than the number of cells rendered per batch.
- var maxToRenderPerBatch = maxToRenderPerBatchOrDefault(props.maxToRenderPerBatch);
-+ var maxFirst = Math.max(0, lastPossibleCellIndex - maxToRenderPerBatch);
- return {
-- first: clamp(0, itemCount - 1 - maxToRenderPerBatch, cells.first),
-- last
-+ first: clamp(0, cells.first, maxFirst),
-+ last: Math.min(lastPossibleCellIndex, cells.last)
- };
- }
- _isNestedWithSameOrientation() {
- var nestedContext = this.context;
- return !!(nestedContext && !!nestedContext.horizontal === horizontalOrDefault(this.props.horizontal));
- }
-- _keyExtractor(item, index, props
-- // $FlowFixMe[missing-local-annot]
-- ) {
-+ static _keyExtractor(item, index, props) {
- if (props.keyExtractor != null) {
- return props.keyExtractor(item, index);
- }
-@@ -1034,7 +1078,12 @@ class VirtualizedList extends StateSafePureComponent {
- this.pushOrUnshift(cells, /*#__PURE__*/React.createElement(VirtualizedListCellContextProvider, {
- cellKey: this._getCellKey() + '-header',
- key: "$header"
-- }, /*#__PURE__*/React.createElement(View, {
-+ }, /*#__PURE__*/React.createElement(View
-+ // We expect that header component will be a single native view so make it
-+ // not collapsable to avoid this view being flattened and make this assumption
-+ // no longer true.
-+ , {
-+ collapsable: false,
- onLayout: this._onLayoutHeader,
- style: [inversionStyle, this.props.ListHeaderComponentStyle]
- },
-@@ -1136,7 +1185,11 @@ class VirtualizedList extends StateSafePureComponent {
- // TODO: Android support
- invertStickyHeaders: this.props.invertStickyHeaders !== undefined ? this.props.invertStickyHeaders : this.props.inverted,
- stickyHeaderIndices,
-- style: inversionStyle ? [inversionStyle, this.props.style] : this.props.style
-+ style: inversionStyle ? [inversionStyle, this.props.style] : this.props.style,
-+ maintainVisibleContentPosition: this.props.maintainVisibleContentPosition != null ? _objectSpread(_objectSpread({}, this.props.maintainVisibleContentPosition), {}, {
-+ // Adjust index to account for ListHeaderComponent.
-+ minIndexForVisible: this.props.maintainVisibleContentPosition.minIndexForVisible + (this.props.ListHeaderComponent ? 1 : 0)
-+ }) : undefined
- });
- this._hasMore = this.state.cellsAroundViewport.last < itemCount - 1;
- var innerRet = /*#__PURE__*/React.createElement(VirtualizedListContextProvider, {
-@@ -1319,8 +1372,12 @@ class VirtualizedList extends StateSafePureComponent {
- onStartReached = _this$props8.onStartReached,
- onStartReachedThreshold = _this$props8.onStartReachedThreshold,
- onEndReached = _this$props8.onEndReached,
-- onEndReachedThreshold = _this$props8.onEndReachedThreshold,
-- initialScrollIndex = _this$props8.initialScrollIndex;
-+ onEndReachedThreshold = _this$props8.onEndReachedThreshold;
-+ // If we have any pending scroll updates it means that the scroll metrics
-+ // are out of date and we should not call any of the edge reached callbacks.
-+ if (this.state.pendingScrollUpdateCount > 0) {
-+ return;
-+ }
- var _this$_scrollMetrics2 = this._scrollMetrics,
- contentLength = _this$_scrollMetrics2.contentLength,
- visibleLength = _this$_scrollMetrics2.visibleLength,
-@@ -1360,16 +1417,10 @@ class VirtualizedList extends StateSafePureComponent {
- // and call onStartReached only once for a given content length,
- // and only if onEndReached is not being executed
- else if (onStartReached != null && this.state.cellsAroundViewport.first === 0 && isWithinStartThreshold && this._scrollMetrics.contentLength !== this._sentStartForContentLength) {
-- // On initial mount when using initialScrollIndex the offset will be 0 initially
-- // and will trigger an unexpected onStartReached. To avoid this we can use
-- // timestamp to differentiate between the initial scroll metrics and when we actually
-- // received the first scroll event.
-- if (!initialScrollIndex || this._scrollMetrics.timestamp !== 0) {
-- this._sentStartForContentLength = this._scrollMetrics.contentLength;
-- onStartReached({
-- distanceFromStart
-- });
-- }
-+ this._sentStartForContentLength = this._scrollMetrics.contentLength;
-+ onStartReached({
-+ distanceFromStart
-+ });
- }
-
- // If the user scrolls away from the start or end and back again,
-@@ -1424,6 +1475,11 @@ class VirtualizedList extends StateSafePureComponent {
- }
- }
- _updateViewableItems(props, cellsAroundViewport) {
-+ // If we have any pending scroll updates it means that the scroll metrics
-+ // are out of date and we should not call any of the visibility callbacks.
-+ if (this.state.pendingScrollUpdateCount > 0) {
-+ return;
-+ }
- this._viewabilityTuples.forEach(tuple => {
- tuple.viewabilityHelper.onUpdate(props, this._scrollMetrics.offset, this._scrollMetrics.visibleLength, this._getFrameMetrics, this._createViewToken, tuple.onViewableItemsChanged, cellsAroundViewport);
- });
-diff --git a/node_modules/react-native-web/src/vendor/react-native/VirtualizedList/index.js b/node_modules/react-native-web/src/vendor/react-native/VirtualizedList/index.js
-index d896fb1..f303b31 100644
---- a/node_modules/react-native-web/src/vendor/react-native/VirtualizedList/index.js
-+++ b/node_modules/react-native-web/src/vendor/react-native/VirtualizedList/index.js
-@@ -75,6 +75,10 @@ type ViewabilityHelperCallbackTuple = {
- type State = {
- renderMask: CellRenderMask,
- cellsAroundViewport: {first: number, last: number},
-+ // Used to track items added at the start of the list for maintainVisibleContentPosition.
-+ firstVisibleItemKey: ?string,
-+ // When > 0 the scroll position available in JS is considered stale and should not be used.
-+ pendingScrollUpdateCount: number,
- };
-
- /**
-@@ -455,9 +459,24 @@ class VirtualizedList extends StateSafePureComponent {
-
- const initialRenderRegion = VirtualizedList._initialRenderRegion(props);
-
-+ const minIndexForVisible =
-+ this.props.maintainVisibleContentPosition?.minIndexForVisible ?? 0;
-+
- this.state = {
- cellsAroundViewport: initialRenderRegion,
- renderMask: VirtualizedList._createRenderMask(props, initialRenderRegion),
-+ firstVisibleItemKey:
-+ this.props.getItemCount(this.props.data) > minIndexForVisible
-+ ? VirtualizedList._getItemKey(this.props, minIndexForVisible)
-+ : null,
-+ // When we have a non-zero initialScrollIndex, we will receive a
-+ // scroll event later so this will prevent the window from updating
-+ // until we get a valid offset.
-+ pendingScrollUpdateCount:
-+ this.props.initialScrollIndex != null &&
-+ this.props.initialScrollIndex > 0
-+ ? 1
-+ : 0,
- };
-
- // REACT-NATIVE-WEB patch to preserve during future RN merges: Support inverted wheel scroller.
-@@ -470,7 +489,7 @@ class VirtualizedList extends StateSafePureComponent {
- const delta = this.props.horizontal
- ? ev.deltaX || ev.wheelDeltaX
- : ev.deltaY || ev.wheelDeltaY;
-- let leftoverDelta = delta;
-+ let leftoverDelta = delta * 5;
- if (isEventTargetScrollable) {
- leftoverDelta = delta < 0
- ? Math.min(delta + scrollOffset, 0)
-@@ -542,6 +561,40 @@ class VirtualizedList extends StateSafePureComponent {
- }
- }
-
-+ static _findItemIndexWithKey(
-+ props: Props,
-+ key: string,
-+ hint: ?number,
-+ ): ?number {
-+ const itemCount = props.getItemCount(props.data);
-+ if (hint != null && hint >= 0 && hint < itemCount) {
-+ const curKey = VirtualizedList._getItemKey(props, hint);
-+ if (curKey === key) {
-+ return hint;
-+ }
-+ }
-+ for (let ii = 0; ii < itemCount; ii++) {
-+ const curKey = VirtualizedList._getItemKey(props, ii);
-+ if (curKey === key) {
-+ return ii;
-+ }
-+ }
-+ return null;
-+ }
-+
-+ static _getItemKey(
-+ props: {
-+ data: Props['data'],
-+ getItem: Props['getItem'],
-+ keyExtractor: Props['keyExtractor'],
-+ ...
-+ },
-+ index: number,
-+ ): string {
-+ const item = props.getItem(props.data, index);
-+ return VirtualizedList._keyExtractor(item, index, props);
-+ }
-+
- static _createRenderMask(
- props: Props,
- cellsAroundViewport: {first: number, last: number},
-@@ -625,6 +678,7 @@ class VirtualizedList extends StateSafePureComponent {
- _adjustCellsAroundViewport(
- props: Props,
- cellsAroundViewport: {first: number, last: number},
-+ pendingScrollUpdateCount: number,
- ): {first: number, last: number} {
- const {data, getItemCount} = props;
- const onEndReachedThreshold = onEndReachedThresholdOrDefault(
-@@ -656,21 +710,9 @@ class VirtualizedList extends StateSafePureComponent {
- ),
- };
- } else {
-- // If we have a non-zero initialScrollIndex and run this before we've scrolled,
-- // we'll wipe out the initialNumToRender rendered elements starting at initialScrollIndex.
-- // So let's wait until we've scrolled the view to the right place. And until then,
-- // we will trust the initialScrollIndex suggestion.
--
-- // Thus, we want to recalculate the windowed render limits if any of the following hold:
-- // - initialScrollIndex is undefined or is 0
-- // - initialScrollIndex > 0 AND scrolling is complete
-- // - initialScrollIndex > 0 AND the end of the list is visible (this handles the case
-- // where the list is shorter than the visible area)
-- if (
-- props.initialScrollIndex &&
-- !this._scrollMetrics.offset &&
-- Math.abs(distanceFromEnd) >= Number.EPSILON
-- ) {
-+ // If we have a pending scroll update, we should not adjust the render window as it
-+ // might override the correct window.
-+ if (pendingScrollUpdateCount > 0) {
- return cellsAroundViewport.last >= getItemCount(data)
- ? VirtualizedList._constrainToItemCount(cellsAroundViewport, props)
- : cellsAroundViewport;
-@@ -779,14 +821,59 @@ class VirtualizedList extends StateSafePureComponent {
- return prevState;
- }
-
-+ let maintainVisibleContentPositionAdjustment: ?number = null;
-+ const prevFirstVisibleItemKey = prevState.firstVisibleItemKey;
-+ const minIndexForVisible =
-+ newProps.maintainVisibleContentPosition?.minIndexForVisible ?? 0;
-+ const newFirstVisibleItemKey =
-+ newProps.getItemCount(newProps.data) > minIndexForVisible
-+ ? VirtualizedList._getItemKey(newProps, minIndexForVisible)
-+ : null;
-+ if (
-+ newProps.maintainVisibleContentPosition != null &&
-+ prevFirstVisibleItemKey != null &&
-+ newFirstVisibleItemKey != null
-+ ) {
-+ if (newFirstVisibleItemKey !== prevFirstVisibleItemKey) {
-+ // Fast path if items were added at the start of the list.
-+ const hint =
-+ itemCount - prevState.renderMask.numCells() + minIndexForVisible;
-+ const firstVisibleItemIndex = VirtualizedList._findItemIndexWithKey(
-+ newProps,
-+ prevFirstVisibleItemKey,
-+ hint,
-+ );
-+ maintainVisibleContentPositionAdjustment =
-+ firstVisibleItemIndex != null
-+ ? firstVisibleItemIndex - minIndexForVisible
-+ : null;
-+ } else {
-+ maintainVisibleContentPositionAdjustment = null;
-+ }
-+ }
-+
- const constrainedCells = VirtualizedList._constrainToItemCount(
-- prevState.cellsAroundViewport,
-+ maintainVisibleContentPositionAdjustment != null
-+ ? {
-+ first:
-+ prevState.cellsAroundViewport.first +
-+ maintainVisibleContentPositionAdjustment,
-+ last:
-+ prevState.cellsAroundViewport.last +
-+ maintainVisibleContentPositionAdjustment,
-+ }
-+ : prevState.cellsAroundViewport,
- newProps,
- );
-
- return {
- cellsAroundViewport: constrainedCells,
- renderMask: VirtualizedList._createRenderMask(newProps, constrainedCells),
-+ firstVisibleItemKey: newFirstVisibleItemKey,
-+ pendingScrollUpdateCount:
-+ maintainVisibleContentPositionAdjustment != null
-+ ? prevState.pendingScrollUpdateCount + 1
-+ : prevState.pendingScrollUpdateCount,
- };
- }
-
-@@ -818,11 +905,11 @@ class VirtualizedList extends StateSafePureComponent {
-
- for (let ii = first; ii <= last; ii++) {
- const item = getItem(data, ii);
-- const key = this._keyExtractor(item, ii, this.props);
-+ const key = VirtualizedList._keyExtractor(item, ii, this.props);
-
- this._indicesToKeys.set(ii, key);
- if (stickyIndicesFromProps.has(ii + stickyOffset)) {
-- this.pushOrUnshift(stickyHeaderIndices, (cells.length));
-+ this.pushOrUnshift(stickyHeaderIndices, cells.length);
- }
-
- const shouldListenForLayout =
-@@ -861,15 +948,19 @@ class VirtualizedList extends StateSafePureComponent {
- props: Props,
- ): {first: number, last: number} {
- const itemCount = props.getItemCount(props.data);
-- const last = Math.min(itemCount - 1, cells.last);
-+ const lastPossibleCellIndex = itemCount - 1;
-
-+ // Constraining `last` may significantly shrink the window. Adjust `first`
-+ // to expand the window if the new `last` results in a new window smaller
-+ // than the number of cells rendered per batch.
- const maxToRenderPerBatch = maxToRenderPerBatchOrDefault(
- props.maxToRenderPerBatch,
- );
-+ const maxFirst = Math.max(0, lastPossibleCellIndex - maxToRenderPerBatch);
-
- return {
-- first: clamp(0, itemCount - 1 - maxToRenderPerBatch, cells.first),
-- last,
-+ first: clamp(0, cells.first, maxFirst),
-+ last: Math.min(lastPossibleCellIndex, cells.last),
- };
- }
-
-@@ -891,15 +982,14 @@ class VirtualizedList extends StateSafePureComponent {
- _getSpacerKey = (isVertical: boolean): string =>
- isVertical ? 'height' : 'width';
-
-- _keyExtractor(
-+ static _keyExtractor(
- item: Item,
- index: number,
- props: {
- keyExtractor?: ?(item: Item, index: number) => string,
- ...
- },
-- // $FlowFixMe[missing-local-annot]
-- ) {
-+ ): string {
- if (props.keyExtractor != null) {
- return props.keyExtractor(item, index);
- }
-@@ -945,6 +1035,10 @@ class VirtualizedList extends StateSafePureComponent {
- cellKey={this._getCellKey() + '-header'}
- key="$header">
- {
- style: inversionStyle
- ? [inversionStyle, this.props.style]
- : this.props.style,
-+ maintainVisibleContentPosition:
-+ this.props.maintainVisibleContentPosition != null
-+ ? {
-+ ...this.props.maintainVisibleContentPosition,
-+ // Adjust index to account for ListHeaderComponent.
-+ minIndexForVisible:
-+ this.props.maintainVisibleContentPosition.minIndexForVisible +
-+ (this.props.ListHeaderComponent ? 1 : 0),
-+ }
-+ : undefined,
- };
-
- this._hasMore = this.state.cellsAroundViewport.last < itemCount - 1;
-@@ -1255,11 +1359,10 @@ class VirtualizedList extends StateSafePureComponent {
- _defaultRenderScrollComponent = props => {
- const onRefresh = props.onRefresh;
- const inversionStyle = this.props.inverted
-- ? this.props.horizontal
-- ? styles.rowReverse
-- : styles.columnReverse
-- : null;
--
-+ ? this.props.horizontal
-+ ? styles.rowReverse
-+ : styles.columnReverse
-+ : null;
- if (this._isNestedWithSameOrientation()) {
- // $FlowFixMe[prop-missing] - Typing ReactNativeComponent revealed errors
- return ;
-@@ -1542,8 +1645,12 @@ class VirtualizedList extends StateSafePureComponent {
- onStartReachedThreshold,
- onEndReached,
- onEndReachedThreshold,
-- initialScrollIndex,
- } = this.props;
-+ // If we have any pending scroll updates it means that the scroll metrics
-+ // are out of date and we should not call any of the edge reached callbacks.
-+ if (this.state.pendingScrollUpdateCount > 0) {
-+ return;
-+ }
- const {contentLength, visibleLength, offset} = this._scrollMetrics;
- let distanceFromStart = offset;
- let distanceFromEnd = contentLength - visibleLength - offset;
-@@ -1595,14 +1702,8 @@ class VirtualizedList extends StateSafePureComponent {
- isWithinStartThreshold &&
- this._scrollMetrics.contentLength !== this._sentStartForContentLength
- ) {
-- // On initial mount when using initialScrollIndex the offset will be 0 initially
-- // and will trigger an unexpected onStartReached. To avoid this we can use
-- // timestamp to differentiate between the initial scroll metrics and when we actually
-- // received the first scroll event.
-- if (!initialScrollIndex || this._scrollMetrics.timestamp !== 0) {
-- this._sentStartForContentLength = this._scrollMetrics.contentLength;
-- onStartReached({distanceFromStart});
-- }
-+ this._sentStartForContentLength = this._scrollMetrics.contentLength;
-+ onStartReached({distanceFromStart});
- }
-
- // If the user scrolls away from the start or end and back again,
-@@ -1729,6 +1830,11 @@ class VirtualizedList extends StateSafePureComponent {
- visibleLength,
- zoomScale,
- };
-+ if (this.state.pendingScrollUpdateCount > 0) {
-+ this.setState(state => ({
-+ pendingScrollUpdateCount: state.pendingScrollUpdateCount - 1,
-+ }));
-+ }
- this._updateViewableItems(this.props, this.state.cellsAroundViewport);
- if (!this.props) {
- return;
-@@ -1844,6 +1950,7 @@ class VirtualizedList extends StateSafePureComponent {
- const cellsAroundViewport = this._adjustCellsAroundViewport(
- props,
- state.cellsAroundViewport,
-+ state.pendingScrollUpdateCount,
- );
- const renderMask = VirtualizedList._createRenderMask(
- props,
-@@ -1874,7 +1981,7 @@ class VirtualizedList extends StateSafePureComponent {
- return {
- index,
- item,
-- key: this._keyExtractor(item, index, props),
-+ key: VirtualizedList._keyExtractor(item, index, props),
- isViewable,
- };
- };
-@@ -1935,13 +2042,12 @@ class VirtualizedList extends StateSafePureComponent {
- inLayout?: boolean,
- ...
- } => {
-- const {data, getItem, getItemCount, getItemLayout} = props;
-+ const {data, getItemCount, getItemLayout} = props;
- invariant(
- index >= 0 && index < getItemCount(data),
- 'Tried to get frame for out of range index ' + index,
- );
-- const item = getItem(data, index);
-- const frame = this._frames[this._keyExtractor(item, index, props)];
-+ const frame = this._frames[VirtualizedList._getItemKey(props, index)];
- if (!frame || frame.index !== index) {
- if (getItemLayout) {
- /* $FlowFixMe[prop-missing] (>=0.63.0 site=react_native_fb) This comment
-@@ -1976,11 +2082,8 @@ class VirtualizedList extends StateSafePureComponent {
- // where it is.
- if (
- focusedCellIndex >= itemCount ||
-- this._keyExtractor(
-- props.getItem(props.data, focusedCellIndex),
-- focusedCellIndex,
-- props,
-- ) !== this._lastFocusedCellKey
-+ VirtualizedList._getItemKey(props, focusedCellIndex) !==
-+ this._lastFocusedCellKey
- ) {
- return [];
- }
-@@ -2021,6 +2124,11 @@ class VirtualizedList extends StateSafePureComponent {
- props: FrameMetricProps,
- cellsAroundViewport: {first: number, last: number},
- ) {
-+ // If we have any pending scroll updates it means that the scroll metrics
-+ // are out of date and we should not call any of the visibility callbacks.
-+ if (this.state.pendingScrollUpdateCount > 0) {
-+ return;
-+ }
- this._viewabilityTuples.forEach(tuple => {
- tuple.viewabilityHelper.onUpdate(
- props,
diff --git a/patches/react-native-web+0.19.9+003+measureInWindow.patch b/patches/react-native-web+0.19.9+002+measureInWindow.patch
similarity index 100%
rename from patches/react-native-web+0.19.9+003+measureInWindow.patch
rename to patches/react-native-web+0.19.9+002+measureInWindow.patch
diff --git a/patches/react-native-web+0.19.9+004+fix-pointer-events.patch b/patches/react-native-web+0.19.9+003+fix-pointer-events.patch
similarity index 100%
rename from patches/react-native-web+0.19.9+004+fix-pointer-events.patch
rename to patches/react-native-web+0.19.9+003+fix-pointer-events.patch
diff --git a/patches/react-native-web+0.19.9+004+fixLastSpacer.patch b/patches/react-native-web+0.19.9+004+fixLastSpacer.patch
new file mode 100644
index 000000000000..fc48c00094dc
--- /dev/null
+++ b/patches/react-native-web+0.19.9+004+fixLastSpacer.patch
@@ -0,0 +1,29 @@
+diff --git a/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js b/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js
+index faeb323..68d740a 100644
+--- a/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js
++++ b/node_modules/react-native-web/dist/vendor/react-native/VirtualizedList/index.js
+@@ -78,14 +78,6 @@ function scrollEventThrottleOrDefault(scrollEventThrottle) {
+ function windowSizeOrDefault(windowSize) {
+ return windowSize !== null && windowSize !== void 0 ? windowSize : 21;
+ }
+-function findLastWhere(arr, predicate) {
+- for (var i = arr.length - 1; i >= 0; i--) {
+- if (predicate(arr[i])) {
+- return arr[i];
+- }
+- }
+- return null;
+-}
+
+ /**
+ * Base implementation for the more convenient [``](https://reactnative.dev/docs/flatlist)
+@@ -1119,7 +1111,8 @@ class VirtualizedList extends StateSafePureComponent {
+ _keylessItemComponentName = '';
+ var spacerKey = this._getSpacerKey(!horizontal);
+ var renderRegions = this.state.renderMask.enumerateRegions();
+- var lastSpacer = findLastWhere(renderRegions, r => r.isSpacer);
++ var lastRegion = renderRegions[renderRegions.length - 1];
++ var lastSpacer = lastRegion?.isSpacer ? lastRegion : null;
+ for (var _iterator = _createForOfIteratorHelperLoose(renderRegions), _step; !(_step = _iterator()).done;) {
+ var section = _step.value;
+ if (section.isSpacer) {
diff --git a/src/CONST.ts b/src/CONST.ts
index b5563825e016..f0f7ab736b78 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -103,6 +103,10 @@ const CONST = {
MERCHANT_NAME_MAX_LENGTH: 255,
+ REQUEST_PREVIEW: {
+ MAX_LENGTH: 83,
+ },
+
CALENDAR_PICKER: {
// Numbers were arbitrarily picked.
MIN_YEAR: CURRENT_YEAR - 100,
@@ -265,7 +269,6 @@ const CONST = {
CHRONOS_IN_CASH: 'chronosInCash',
DEFAULT_ROOMS: 'defaultRooms',
BETA_COMMENT_LINKING: 'commentLinking',
- POLICY_ROOMS: 'policyRooms',
VIOLATIONS: 'violations',
REPORT_FIELDS: 'reportFields',
},
@@ -476,7 +479,9 @@ const CONST = {
ONFIDO_TERMS_OF_SERVICE_URL: 'https://onfido.com/terms-of-service/',
// Use Environment.getEnvironmentURL to get the complete URL with port number
DEV_NEW_EXPENSIFY_URL: 'https://dev.new.expensify.com:',
- EXPENSIFY_INBOX_URL: 'https://www.expensify.com/inbox',
+ OLDDOT_URLS: {
+ INBOX: 'inbox',
+ },
SIGN_IN_FORM_WIDTH: 300,
@@ -524,6 +529,7 @@ const CONST = {
TASKCOMPLETED: 'TASKCOMPLETED',
TASKEDITED: 'TASKEDITED',
TASKREOPENED: 'TASKREOPENED',
+ ACTIONABLEMENTIONWHISPER: 'ACTIONABLEMENTIONWHISPER',
POLICYCHANGELOG: {
ADD_APPROVER_RULE: 'POLICYCHANGELOG_ADD_APPROVER_RULE',
ADD_BUDGET: 'POLICYCHANGELOG_ADD_BUDGET',
@@ -597,6 +603,12 @@ const CONST = {
},
THREAD_DISABLED: ['CREATED'],
},
+ CANCEL_PAYMENT_REASONS: {
+ ADMIN: 'CANCEL_REASON_ADMIN',
+ },
+ ACTIONABLE_MENTION_WHISPER_RESOLUTION: {
+ INVITE: 'invited',
+ },
ARCHIVE_REASON: {
DEFAULT: 'default',
ACCOUNT_CLOSED: 'accountClosed',
@@ -1177,6 +1189,11 @@ const CONST = {
EXPENSIFY: 'Expensify',
VBBA: 'ACH',
},
+ ACTION: {
+ EDIT: 'edit',
+ CREATE: 'create',
+ },
+ DEFAULT_AMOUNT: 0,
TYPE: {
SEND: 'send',
SPLIT: 'split',
@@ -1361,6 +1378,7 @@ const CONST = {
DIGITS_AND_PLUS: /^\+?[0-9]*$/,
ALPHABETIC_AND_LATIN_CHARS: /^[\p{Script=Latin} ]*$/u,
NON_ALPHABETIC_AND_NON_LATIN_CHARS: /[^\p{Script=Latin}]/gu,
+ ACCENT_LATIN_CHARS: /[\u00C0-\u017F]/g,
POSITIVE_INTEGER: /^\d+$/,
PO_BOX: /\b[P|p]?(OST|ost)?\.?\s*[O|o|0]?(ffice|FFICE)?\.?\s*[B|b][O|o|0]?[X|x]?\.?\s+[#]?(\d+)\b/,
ANY_VALUE: /^.+$/,
@@ -1418,6 +1436,7 @@ const CONST = {
ROUTES: {
VALIDATE_LOGIN: /\/v($|(\/\/*))/,
UNLINK_LOGIN: /\/u($|(\/\/*))/,
+ REDUNDANT_SLASHES: /(\/{2,})|(\/$)/g,
},
TIME_STARTS_01: /^01:\d{2} [AP]M$/,
@@ -2715,7 +2734,7 @@ const CONST = {
EXPECTED_OUTPUT: 'FCFA 123,457',
},
- PATHS_TO_TREAT_AS_EXTERNAL: ['NewExpensify.dmg'],
+ PATHS_TO_TREAT_AS_EXTERNAL: ['NewExpensify.dmg', 'docs/index.html'],
// Test tool menu parameters
TEST_TOOL: {
@@ -2885,8 +2904,10 @@ const CONST = {
ATTACHMENT: 'common.attachment',
},
TEACHERS_UNITE: {
- PUBLIC_ROOM_ID: '7470147100835202',
- POLICY_ID: 'B795B6319125BDF2',
+ PROD_PUBLIC_ROOM_ID: '7470147100835202',
+ PROD_POLICY_ID: 'B795B6319125BDF2',
+ TEST_PUBLIC_ROOM_ID: '207591744844000',
+ TEST_POLICY_ID: 'ABD1345ED7293535',
POLICY_NAME: 'Expensify.org / Teachers Unite!',
PUBLIC_ROOM_NAME: '#teachers-unite',
},
@@ -2950,6 +2971,7 @@ const CONST = {
MAPBOX: {
PADDING: 50,
DEFAULT_ZOOM: 10,
+ SINGLE_MARKER_ZOOM: 15,
DEFAULT_COORDINATE: [-122.4021, 37.7911],
STYLE_URL: 'mapbox://styles/expensify/cllcoiqds00cs01r80kp34tmq',
},
@@ -3054,6 +3076,47 @@ const CONST = {
CAROUSEL: 3,
},
+ BRICK_ROAD: {
+ GBR: 'GBR',
+ RBR: 'RBR',
+ },
+
+ VIOLATIONS: {
+ ALL_TAG_LEVELS_REQUIRED: 'allTagLevelsRequired',
+ AUTO_REPORTED_REJECTED_EXPENSE: 'autoReportedRejectedExpense',
+ BILLABLE_EXPENSE: 'billableExpense',
+ CASH_EXPENSE_WITH_NO_RECEIPT: 'cashExpenseWithNoReceipt',
+ CATEGORY_OUT_OF_POLICY: 'categoryOutOfPolicy',
+ CONVERSION_SURCHARGE: 'conversionSurcharge',
+ CUSTOM_UNIT_OUT_OF_POLICY: 'customUnitOutOfPolicy',
+ DUPLICATED_TRANSACTION: 'duplicatedTransaction',
+ FIELD_REQUIRED: 'fieldRequired',
+ FUTURE_DATE: 'futureDate',
+ INVOICE_MARKUP: 'invoiceMarkup',
+ MAX_AGE: 'maxAge',
+ MISSING_CATEGORY: 'missingCategory',
+ MISSING_COMMENT: 'missingComment',
+ MISSING_TAG: 'missingTag',
+ MODIFIED_AMOUNT: 'modifiedAmount',
+ MODIFIED_DATE: 'modifiedDate',
+ NON_EXPENSIWORKS_EXPENSE: 'nonExpensiworksExpense',
+ OVER_AUTO_APPROVAL_LIMIT: 'overAutoApprovalLimit',
+ OVER_CATEGORY_LIMIT: 'overCategoryLimit',
+ OVER_LIMIT: 'overLimit',
+ OVER_LIMIT_ATTENDEE: 'overLimitAttendee',
+ PER_DAY_LIMIT: 'perDayLimit',
+ RECEIPT_NOT_SMART_SCANNED: 'receiptNotSmartScanned',
+ RECEIPT_REQUIRED: 'receiptRequired',
+ RTER: 'rter',
+ SMARTSCAN_FAILED: 'smartscanFailed',
+ SOME_TAG_LEVELS_REQUIRED: 'someTagLevelsRequired',
+ TAG_OUT_OF_POLICY: 'tagOutOfPolicy',
+ TAX_AMOUNT_CHANGED: 'taxAmountChanged',
+ TAX_OUT_OF_POLICY: 'taxOutOfPolicy',
+ TAX_RATE_CHANGED: 'taxRateChanged',
+ TAX_REQUIRED: 'taxRequired',
+ },
+
/** Context menu types */
CONTEXT_MENU_TYPES: {
LINK: 'LINK',
diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts
index 89ddbdc06883..98e3856f4544 100755
--- a/src/ONYXKEYS.ts
+++ b/src/ONYXKEYS.ts
@@ -458,6 +458,7 @@ type OnyxValues = {
[ONYXKEYS.COLLECTION.REPORT_USER_IS_LEAVING_ROOM]: boolean;
[ONYXKEYS.COLLECTION.SECURITY_GROUP]: OnyxTypes.SecurityGroup;
[ONYXKEYS.COLLECTION.TRANSACTION]: OnyxTypes.Transaction;
+ [ONYXKEYS.COLLECTION.TRANSACTION_DRAFT]: OnyxTypes.Transaction;
[ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS]: OnyxTypes.RecentlyUsedTags;
[ONYXKEYS.COLLECTION.SELECTED_TAB]: string;
[ONYXKEYS.COLLECTION.PRIVATE_NOTES_DRAFT]: string;
diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index 35fa4bbf0837..37003a09a0cd 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -286,10 +286,6 @@ const ROUTES = {
route: ':iouType/new/merchant/:reportID?',
getRoute: (iouType: string, reportID = '') => `${iouType}/new/merchant/${reportID}` as const,
},
- MONEY_REQUEST_WAYPOINT: {
- route: ':iouType/new/waypoint/:waypointIndex',
- getRoute: (iouType: string, waypointIndex: number) => `${iouType}/new/waypoint/${waypointIndex}` as const,
- },
MONEY_REQUEST_RECEIPT: {
route: ':iouType/new/receipt/:reportID?',
getRoute: (iouType: string, reportID = '') => `${iouType}/new/receipt/${reportID}` as const,
@@ -298,10 +294,6 @@ const ROUTES = {
route: ':iouType/new/address/:reportID?',
getRoute: (iouType: string, reportID = '') => `${iouType}/new/address/${reportID}` as const,
},
- MONEY_REQUEST_EDIT_WAYPOINT: {
- route: 'r/:threadReportID/edit/distance/:transactionID/waypoint/:waypointIndex',
- getRoute: (threadReportID: number, transactionID: string, waypointIndex: number) => `r/${threadReportID}/edit/distance/${transactionID}/waypoint/${waypointIndex}` as const,
- },
MONEY_REQUEST_DISTANCE_TAB: {
route: ':iouType/new/:reportID?/distance',
getRoute: (iouType: string, reportID = '') => `${iouType}/new/${reportID}/distance` as const,
@@ -314,13 +306,13 @@ const ROUTES = {
getRoute: (iouType: ValueOf, transactionID: string, reportID: string) => `create/${iouType}/start/${transactionID}/${reportID}` as const,
},
MONEY_REQUEST_STEP_CONFIRMATION: {
- route: 'create/:iouType/confirmation/:transactionID/:reportID/',
- getRoute: (iouType: ValueOf, transactionID: string, reportID: string) => `create/${iouType}/confirmation/${transactionID}/${reportID}/` as const,
+ route: 'create/:iouType/confirmation/:transactionID/:reportID',
+ getRoute: (iouType: ValueOf, transactionID: string, reportID: string) => `create/${iouType}/confirmation/${transactionID}/${reportID}` as const,
},
MONEY_REQUEST_STEP_AMOUNT: {
- route: 'create/:iouType/amount/:transactionID/:reportID/',
+ route: 'create/:iouType/amount/:transactionID/:reportID',
getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') =>
- getUrlWithBackToParam(`create/${iouType}/amount/${transactionID}/${reportID}/`, backTo),
+ getUrlWithBackToParam(`create/${iouType}/amount/${transactionID}/${reportID}`, backTo),
},
MONEY_REQUEST_STEP_TAX_RATE: {
route: 'create/:iouType/taxRate/:transactionID/:reportID?',
@@ -333,54 +325,54 @@ const ROUTES = {
getUrlWithBackToParam(`create/${iouType}/taxAmount/${transactionID}/${reportID}`, backTo),
},
MONEY_REQUEST_STEP_CATEGORY: {
- route: 'create/:iouType/category/:transactionID/:reportID/',
+ route: 'create/:iouType/category/:transactionID/:reportID',
getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') =>
- getUrlWithBackToParam(`create/${iouType}/category/${transactionID}/${reportID}/`, backTo),
+ getUrlWithBackToParam(`create/${iouType}/category/${transactionID}/${reportID}`, backTo),
},
MONEY_REQUEST_STEP_CURRENCY: {
- route: 'create/:iouType/currency/:transactionID/:reportID/:pageIndex?/',
+ route: 'create/:iouType/currency/:transactionID/:reportID/:pageIndex?',
getRoute: (iouType: ValueOf, transactionID: string, reportID: string, pageIndex = '', backTo = '') =>
getUrlWithBackToParam(`create/${iouType}/currency/${transactionID}/${reportID}/${pageIndex}`, backTo),
},
MONEY_REQUEST_STEP_DATE: {
- route: 'create/:iouType/date/:transactionID/:reportID/',
+ route: 'create/:iouType/date/:transactionID/:reportID',
getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') =>
- getUrlWithBackToParam(`create/${iouType}/date/${transactionID}/${reportID}/`, backTo),
+ getUrlWithBackToParam(`create/${iouType}/date/${transactionID}/${reportID}`, backTo),
},
MONEY_REQUEST_STEP_DESCRIPTION: {
- route: 'create/:iouType/description/:transactionID/:reportID/',
+ route: 'create/:iouType/description/:transactionID/:reportID',
getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') =>
- getUrlWithBackToParam(`create/${iouType}/description/${transactionID}/${reportID}/`, backTo),
+ getUrlWithBackToParam(`create/${iouType}/description/${transactionID}/${reportID}`, backTo),
},
MONEY_REQUEST_STEP_DISTANCE: {
- route: 'create/:iouType/distance/:transactionID/:reportID/',
+ route: 'create/:iouType/distance/:transactionID/:reportID',
getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') =>
- getUrlWithBackToParam(`create/${iouType}/distance/${transactionID}/${reportID}/`, backTo),
+ getUrlWithBackToParam(`create/${iouType}/distance/${transactionID}/${reportID}`, backTo),
},
MONEY_REQUEST_STEP_MERCHANT: {
- route: 'create/:iouType/merchante/:transactionID/:reportID/',
+ route: 'create/:iouType/merchant/:transactionID/:reportID',
getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') =>
- getUrlWithBackToParam(`create/${iouType}/merchante/${transactionID}/${reportID}/`, backTo),
+ getUrlWithBackToParam(`create/${iouType}/merchant/${transactionID}/${reportID}`, backTo),
},
MONEY_REQUEST_STEP_PARTICIPANTS: {
- route: 'create/:iouType/participants/:transactionID/:reportID/',
+ route: 'create/:iouType/participants/:transactionID/:reportID',
getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') =>
- getUrlWithBackToParam(`create/${iouType}/participants/${transactionID}/${reportID}/`, backTo),
+ getUrlWithBackToParam(`create/${iouType}/participants/${transactionID}/${reportID}`, backTo),
},
MONEY_REQUEST_STEP_SCAN: {
- route: 'create/:iouType/scan/:transactionID/:reportID/',
- getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') =>
- getUrlWithBackToParam(`create/${iouType}/scan/${transactionID}/${reportID}/`, backTo),
+ route: ':action/:iouType/scan/:transactionID/:reportID',
+ getRoute: (action: ValueOf, iouType: ValueOf, transactionID: string, reportID: string, backTo = '') =>
+ getUrlWithBackToParam(`${action}/${iouType}/scan/${transactionID}/${reportID}`, backTo),
},
MONEY_REQUEST_STEP_TAG: {
- route: 'create/:iouType/tag/:transactionID/:reportID/',
+ route: 'create/:iouType/tag/:transactionID/:reportID',
getRoute: (iouType: ValueOf, transactionID: string, reportID: string, backTo = '') =>
- getUrlWithBackToParam(`create/${iouType}/tag/${transactionID}/${reportID}/`, backTo),
+ getUrlWithBackToParam(`create/${iouType}/tag/${transactionID}/${reportID}`, backTo),
},
MONEY_REQUEST_STEP_WAYPOINT: {
- route: 'create/:iouType/waypoint/:transactionID/:reportID/:pageIndex/',
- getRoute: (iouType: ValueOf, transactionID: string, reportID: string, pageIndex = '', backTo = '') =>
- getUrlWithBackToParam(`create/${iouType}/waypoint/${transactionID}/${reportID}/${pageIndex}`, backTo),
+ route: ':action/:iouType/waypoint/:transactionID/:reportID/:pageIndex',
+ getRoute: (action: ValueOf, iouType: ValueOf, transactionID: string, reportID: string, pageIndex = '', backTo = '') =>
+ getUrlWithBackToParam(`${action}/${iouType}/waypoint/${transactionID}/${reportID}/${pageIndex}`, backTo),
},
// This URL is used as a redirect to one of the create tabs below. This is so that we can message users with a link
// straight to those flows without needing to have optimistic transaction and report IDs.
@@ -479,6 +471,7 @@ const ROUTES = {
route: 'referral/:contentType',
getRoute: (contentType: string) => `referral/${contentType}` as const,
},
+ PROCESS_MONEY_REQUEST_HOLD: 'hold-request-educational',
} as const;
export {getUrlWithBackToParam};
diff --git a/src/SCREENS.ts b/src/SCREENS.ts
index 91c4153bacd2..703cb309d641 100644
--- a/src/SCREENS.ts
+++ b/src/SCREENS.ts
@@ -108,6 +108,7 @@ const SCREENS = {
ROOM_MEMBERS: 'RoomMembers',
ROOM_INVITE: 'RoomInvite',
REFERRAL: 'Referral',
+ PROCESS_MONEY_REQUEST_HOLD: 'ProcessMoneyRequestHold',
},
SIGN_IN_WITH_APPLE_DESKTOP: 'AppleSignInDesktop',
SIGN_IN_WITH_GOOGLE_DESKTOP: 'GoogleSignInDesktop',
@@ -231,6 +232,7 @@ const SCREENS = {
SIGN_IN_ROOT: 'SignIn_Root',
DETAILS_ROOT: 'Details_Root',
PROFILE_ROOT: 'Profile_Root',
+ PROCESS_MONEY_REQUEST_HOLD_ROOT: 'ProcessMoneyRequestHold_Root',
REPORT_WELCOME_MESSAGE_ROOT: 'Report_WelcomeMessage_Root',
REPORT_PARTICIPANTS_ROOT: 'ReportParticipants_Root',
ROOM_MEMBERS_ROOT: 'RoomMembers_Root',
diff --git a/src/TIMEZONES.ts b/src/TIMEZONES.ts
index 1eb49f291495..238563134872 100644
--- a/src/TIMEZONES.ts
+++ b/src/TIMEZONES.ts
@@ -1,5 +1,6 @@
+/* eslint-disable @typescript-eslint/naming-convention */
// All timezones were taken from: https://raw.githubusercontent.com/leon-do/Timezones/main/timezone.json
-export default [
+const TIMEZONES = [
'Africa/Abidjan',
'Africa/Accra',
'Africa/Addis_Ababa',
@@ -419,3 +420,137 @@ export default [
'Pacific/Wake',
'Pacific/Wallis',
] as const;
+
+/**
+ * The timezones supported in browser and on native devices differ, so we must map each timezone to its supported equivalent.
+ * Data sourced from https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
+ */
+const timezoneBackwardMap: Record = {
+ 'Africa/Asmera': 'Africa/Nairobi',
+ 'Africa/Timbuktu': 'Africa/Abidjan',
+ 'America/Argentina/ComodRivadavia': 'America/Argentina/Catamarca',
+ 'America/Atka': 'America/Adak',
+ 'America/Buenos_Aires': 'America/Argentina/Buenos_Aires',
+ 'America/Catamarca': 'America/Argentina/Catamarca',
+ 'America/Coral_Harbour': 'America/Panama',
+ 'America/Cordoba': 'America/Argentina/Cordoba',
+ 'America/Ensenada': 'America/Tijuana',
+ 'America/Fort_Wayne': 'America/Indiana/Indianapolis',
+ 'America/Godthab': 'America/Nuuk',
+ 'America/Indianapolis': 'America/Indiana/Indianapolis',
+ 'America/Jujuy': 'America/Argentina/Jujuy',
+ 'America/Knox_IN': 'America/Indiana/Knox',
+ 'America/Louisville': 'America/Kentucky/Louisville',
+ 'America/Mendoza': 'America/Argentina/Mendoza',
+ 'America/Montreal': 'America/Toronto',
+ 'America/Nipigon': 'America/Toronto',
+ 'America/Pangnirtung': 'America/Iqaluit',
+ 'America/Porto_Acre': 'America/Rio_Branco',
+ 'America/Rainy_River': 'America/Winnipeg',
+ 'America/Rosario': 'America/Argentina/Cordoba',
+ 'America/Santa_Isabel': 'America/Tijuana',
+ 'America/Shiprock': 'America/Denver',
+ 'America/Thunder_Bay': 'America/Toronto',
+ 'America/Virgin': 'America/Puerto_Rico',
+ 'America/Yellowknife': 'America/Edmonton',
+ 'Antarctica/South_Pole': 'Pacific/Auckland',
+ 'Asia/Ashkhabad': 'Asia/Ashgabat',
+ 'Asia/Calcutta': 'Asia/Kolkata',
+ 'Asia/Chongqing': 'Asia/Shanghai',
+ 'Asia/Chungking': 'Asia/Shanghai',
+ 'Asia/Dacca': 'Asia/Dhaka',
+ 'Asia/Harbin': 'Asia/Shanghai',
+ 'Asia/Istanbul': 'Europe/Istanbul',
+ 'Asia/Kashgar': 'Asia/Urumqi',
+ 'Asia/Katmandu': 'Asia/Kathmandu',
+ 'Asia/Macao': 'Asia/Macau',
+ 'Asia/Rangoon': 'Asia/Yangon',
+ 'Asia/Saigon': 'Asia/Ho_Chi_Minh',
+ 'Asia/Tel_Aviv': 'Asia/Jerusalem',
+ 'Asia/Thimbu': 'Asia/Thimphu',
+ 'Asia/Ujung_Pandang': 'Asia/Makassar',
+ 'Asia/Ulan_Bator': 'Asia/Ulaanbaatar',
+ 'Atlantic/Faeroe': 'Atlantic/Faroe',
+ 'Atlantic/Jan_Mayen': 'Europe/Berlin',
+ 'Australia/ACT': 'Australia/Sydney',
+ 'Australia/Canberra': 'Australia/Sydney',
+ 'Australia/Currie': 'Australia/Hobart',
+ 'Australia/LHI': 'Australia/Lord_Howe',
+ 'Australia/NSW': 'Australia/Sydney',
+ 'Australia/North': 'Australia/Darwin',
+ 'Australia/Queensland': 'Australia/Brisbane',
+ 'Australia/South': 'Australia/Adelaide',
+ 'Australia/Tasmania': 'Australia/Hobart',
+ 'Australia/Victoria': 'Australia/Melbourne',
+ 'Australia/West': 'Australia/Perth',
+ 'Australia/Yancowinna': 'Australia/Broken_Hill',
+ 'Brazil/Acre': 'America/Rio_Branco',
+ 'Brazil/DeNoronha': 'America/Noronha',
+ 'Brazil/East': 'America/Sao_Paulo',
+ 'Brazil/West': 'America/Manaus',
+ 'Canada/Atlantic': 'America/Halifax',
+ 'Canada/Central': 'America/Winnipeg',
+ 'Canada/Eastern': 'America/Toronto',
+ 'Canada/Mountain': 'America/Edmonton',
+ 'Canada/Newfoundland': 'America/St_Johns',
+ 'Canada/Pacific': 'America/Vancouver',
+ 'Canada/Saskatchewan': 'America/Regina',
+ 'Canada/Yukon': 'America/Whitehorse',
+ 'Chile/Continental': 'America/Santiago',
+ 'Chile/EasterIsland': 'Pacific/Easter',
+ Cuba: 'America/Havana',
+ Egypt: 'Africa/Cairo',
+ Eire: 'Europe/Dublin',
+ 'Europe/Belfast': 'Europe/London',
+ 'Europe/Kiev': 'Europe/Kyiv',
+ 'Europe/Nicosia': 'Asia/Nicosia',
+ 'Europe/Tiraspol': 'Europe/Chisinau',
+ 'Europe/Uzhgorod': 'Europe/Kyiv',
+ 'Europe/Zaporozhye': 'Europe/Kyiv',
+ GB: 'Europe/London',
+ 'GB-Eire': 'Europe/London',
+ Hongkong: 'Asia/Hong_Kong',
+ Iceland: 'Africa/Abidjan',
+ Iran: 'Asia/Tehran',
+ Israel: 'Asia/Jerusalem',
+ Jamaica: 'America/Jamaica',
+ Japan: 'Asia/Tokyo',
+ Kwajalein: 'Pacific/Kwajalein',
+ Libya: 'Africa/Tripoli',
+ 'Mexico/BajaNorte': 'America/Tijuana',
+ 'Mexico/BajaSur': 'America/Mazatlan',
+ 'Mexico/General': 'America/Mexico_City',
+ NZ: 'Pacific/Auckland',
+ 'NZ-CHAT': 'Pacific/Chatham',
+ Navajo: 'America/Denver',
+ PRC: 'Asia/Shanghai',
+ 'Pacific/Enderbury': 'Pacific/Kanton',
+ 'Pacific/Johnston': 'Pacific/Honolulu',
+ 'Pacific/Ponape': 'Pacific/Guadalcanal',
+ 'Pacific/Samoa': 'Pacific/Pago_Pago',
+ 'Pacific/Truk': 'Pacific/Port_Moresby',
+ 'Pacific/Yap': 'Pacific/Port_Moresby',
+ Poland: 'Europe/Warsaw',
+ Portugal: 'Europe/Lisbon',
+ ROC: 'Asia/Taipei',
+ ROK: 'Asia/Seoul',
+ Singapore: 'Asia/Singapore',
+ Turkey: 'Europe/Istanbul',
+ 'US/Alaska': 'America/Anchorage',
+ 'US/Aleutian': 'America/Adak',
+ 'US/Arizona': 'America/Phoenix',
+ 'US/Central': 'America/Chicago',
+ 'US/East-Indiana': 'America/Indiana/Indianapolis',
+ 'US/Eastern': 'America/New_York',
+ 'US/Hawaii': 'Pacific/Honolulu',
+ 'US/Indiana-Starke': 'America/Indiana/Knox',
+ 'US/Michigan': 'America/Detroit',
+ 'US/Mountain': 'America/Denver',
+ 'US/Pacific': 'America/Los_Angeles',
+ 'US/Samoa': 'Pacific/Pago_Pago',
+ 'W-SU': 'Europe/Moscow',
+};
+
+export {timezoneBackwardMap};
+
+export default TIMEZONES;
diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js
index 656694a785a3..a5160a13f8e9 100644
--- a/src/components/AddPlaidBankAccount.js
+++ b/src/components/AddPlaidBankAccount.js
@@ -249,7 +249,6 @@ function AddPlaidBankAccount({
height={iconSize}
width={iconSize}
additionalStyles={iconStyles}
- fill={theme.icon}
/>
{bankName}
diff --git a/src/components/AddressSearch/index.js b/src/components/AddressSearch/index.js
index 31b04a3d954f..357f5af8cb58 100644
--- a/src/components/AddressSearch/index.js
+++ b/src/components/AddressSearch/index.js
@@ -349,6 +349,7 @@ function AddressSearch({
lat: successData.coords.latitude,
lng: successData.coords.longitude,
address: CONST.YOUR_LOCATION_TEXT,
+ name: CONST.YOUR_LOCATION_TEXT,
};
onPress(location);
},
@@ -362,7 +363,7 @@ function AddressSearch({
},
{
maximumAge: 0, // No cache, always get fresh location info
- timeout: 5000,
+ timeout: 30000,
},
);
};
diff --git a/src/components/AmountTextInput.js b/src/components/AmountTextInput.js
deleted file mode 100644
index 25e1ce6f05ec..000000000000
--- a/src/components/AmountTextInput.js
+++ /dev/null
@@ -1,89 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import useStyleUtils from '@hooks/useStyleUtils';
-import useThemeStyles from '@hooks/useThemeStyles';
-import CONST from '@src/CONST';
-import refPropTypes from './refPropTypes';
-import TextInput from './TextInput';
-
-const propTypes = {
- /** Formatted amount in local currency */
- formattedAmount: PropTypes.string.isRequired,
-
- /** A ref to forward to amount text input */
- forwardedRef: refPropTypes,
-
- /** Function to call when amount in text input is changed */
- onChangeAmount: PropTypes.func.isRequired,
-
- /** Placeholder value for amount text input */
- placeholder: PropTypes.string.isRequired,
-
- /** Selection Object */
- selection: PropTypes.shape({
- start: PropTypes.number,
- end: PropTypes.number,
- }),
-
- /** Function to call when selection in text input is changed */
- onSelectionChange: PropTypes.func,
-
- /** Style for the input */
- style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
-
- /** Style for the container */
- containerStyles: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
-
- /** Function to call to handle key presses in the text input */
- onKeyPress: PropTypes.func,
-};
-
-const defaultProps = {
- forwardedRef: undefined,
- selection: undefined,
- onSelectionChange: () => {},
- onKeyPress: () => {},
- style: {},
- containerStyles: {},
-};
-
-function AmountTextInput(props) {
- const styles = useThemeStyles();
- const StyleUtils = useStyleUtils();
- return (
-
- );
-}
-
-AmountTextInput.propTypes = propTypes;
-AmountTextInput.defaultProps = defaultProps;
-AmountTextInput.displayName = 'AmountTextInput';
-
-const AmountTextInputWithRef = React.forwardRef((props, ref) => (
-
-));
-
-AmountTextInputWithRef.displayName = 'AmountTextInputWithRef';
-
-export default AmountTextInputWithRef;
diff --git a/src/components/AmountTextInput.tsx b/src/components/AmountTextInput.tsx
new file mode 100644
index 000000000000..0f3416076cc0
--- /dev/null
+++ b/src/components/AmountTextInput.tsx
@@ -0,0 +1,64 @@
+import React from 'react';
+import type {StyleProp, TextStyle, ViewStyle} from 'react-native';
+import useThemeStyles from '@hooks/useThemeStyles';
+import CONST from '@src/CONST';
+import type {TextSelection} from './Composer/types';
+import TextInput from './TextInput';
+import type {BaseTextInputRef} from './TextInput/BaseTextInput/types';
+
+type AmountTextInputProps = {
+ /** Formatted amount in local currency */
+ formattedAmount: string;
+
+ /** Function to call when amount in text input is changed */
+ onChangeAmount: (amount: string) => void;
+
+ /** Placeholder value for amount text input */
+ placeholder: string;
+
+ /** Selection Object */
+ selection?: TextSelection;
+
+ /** Function to call when selection in text input is changed */
+ onSelectionChange?: () => void;
+
+ /** Style for the input */
+ style?: StyleProp;
+
+ /** Style for the container */
+ touchableInputWrapperStyle?: StyleProp;
+
+ /** Function to call to handle key presses in the text input */
+ onKeyPress?: () => void;
+};
+
+function AmountTextInput(
+ {formattedAmount, onChangeAmount, placeholder, selection, onSelectionChange, style, touchableInputWrapperStyle, onKeyPress}: AmountTextInputProps,
+ ref: BaseTextInputRef,
+) {
+ const styles = useThemeStyles();
+ return (
+
+ );
+}
+
+AmountTextInput.displayName = 'AmountTextInput';
+
+export default React.forwardRef(AmountTextInput);
diff --git a/src/components/AnchorForAttachmentsOnly/BaseAnchorForAttachmentsOnly.js b/src/components/AnchorForAttachmentsOnly/BaseAnchorForAttachmentsOnly.tsx
similarity index 52%
rename from src/components/AnchorForAttachmentsOnly/BaseAnchorForAttachmentsOnly.js
rename to src/components/AnchorForAttachmentsOnly/BaseAnchorForAttachmentsOnly.tsx
index 6161ba140726..df8a0a30b129 100644
--- a/src/components/AnchorForAttachmentsOnly/BaseAnchorForAttachmentsOnly.js
+++ b/src/components/AnchorForAttachmentsOnly/BaseAnchorForAttachmentsOnly.tsx
@@ -1,6 +1,6 @@
-import PropTypes from 'prop-types';
import React from 'react';
import {withOnyx} from 'react-native-onyx';
+import type {OnyxEntry} from 'react-native-onyx';
import AttachmentView from '@components/Attachments/AttachmentView';
import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
import {ShowContextMenuContext, showContextMenuForReport} from '@components/ShowContextMenuContext';
@@ -10,59 +10,52 @@ import * as ReportUtils from '@libs/ReportUtils';
import * as Download from '@userActions/Download';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
-import {defaultProps as anchorForAttachmentsOnlyDefaultProps, propTypes as anchorForAttachmentsOnlyPropTypes} from './anchorForAttachmentsOnlyPropTypes';
-
-const propTypes = {
- /** Press in handler for the link */
- onPressIn: PropTypes.func,
-
- /** Press out handler for the link */
- onPressOut: PropTypes.func,
+import type {Download as OnyxDownload} from '@src/types/onyx';
+import type AnchorForAttachmentsOnlyProps from './types';
+type BaseAnchorForAttachmentsOnlyOnyxProps = {
/** If a file download is happening */
- download: PropTypes.shape({
- isDownloading: PropTypes.bool.isRequired,
- }),
-
- ...anchorForAttachmentsOnlyPropTypes,
+ download: OnyxEntry;
};
-const defaultProps = {
- onPressIn: undefined,
- onPressOut: undefined,
- download: {isDownloading: false},
- ...anchorForAttachmentsOnlyDefaultProps,
-};
+type BaseAnchorForAttachmentsOnlyProps = AnchorForAttachmentsOnlyProps &
+ BaseAnchorForAttachmentsOnlyOnyxProps & {
+ /** Press in handler for the link */
+ onPressIn?: () => void;
+
+ /** Press out handler for the link */
+ onPressOut?: () => void;
+ };
-function BaseAnchorForAttachmentsOnly(props) {
- const sourceURL = props.source;
- const sourceURLWithAuth = addEncryptedAuthTokenToURL(sourceURL);
- const sourceID = (sourceURL.match(CONST.REGEX.ATTACHMENT_ID) || [])[1];
- const fileName = props.displayName;
+function BaseAnchorForAttachmentsOnly({style, source = '', displayName = '', download, onPressIn, onPressOut}: BaseAnchorForAttachmentsOnlyProps) {
+ const sourceURLWithAuth = addEncryptedAuthTokenToURL(source);
+ const sourceID = (source.match(CONST.REGEX.ATTACHMENT_ID) ?? [])[1];
- const isDownloading = props.download && props.download.isDownloading;
+ const isDownloading = download?.isDownloading ?? false;
return (
{({anchor, report, action, checkIfContextMenuActive}) => (
{
if (isDownloading) {
return;
}
Download.setDownload(sourceID, true);
- fileDownload(sourceURLWithAuth, fileName).then(() => Download.setDownload(sourceID, false));
+ fileDownload(sourceURLWithAuth, displayName).then(() => Download.setDownload(sourceID, false));
}}
- onPressIn={props.onPressIn}
- onPressOut={props.onPressOut}
+ onPressIn={onPressIn}
+ onPressOut={onPressOut}
+ // @ts-expect-error TODO: Remove this once ShowContextMenuContext (https://github.com/Expensify/App/issues/24980) is migrated to TypeScript.
onLongPress={(event) => showContextMenuForReport(event, anchor, report.reportID, action, checkIfContextMenuActive, ReportUtils.isArchivedRoom(report))}
- accessibilityLabel={fileName}
+ accessibilityLabel={displayName}
role={CONST.ROLE.BUTTON}
>
@@ -73,13 +66,11 @@ function BaseAnchorForAttachmentsOnly(props) {
}
BaseAnchorForAttachmentsOnly.displayName = 'BaseAnchorForAttachmentsOnly';
-BaseAnchorForAttachmentsOnly.propTypes = propTypes;
-BaseAnchorForAttachmentsOnly.defaultProps = defaultProps;
-export default withOnyx({
+export default withOnyx({
download: {
key: ({source}) => {
- const sourceID = (source.match(CONST.REGEX.ATTACHMENT_ID) || [])[1];
+ const sourceID = (source?.match(CONST.REGEX.ATTACHMENT_ID) ?? [])[1];
return `${ONYXKEYS.COLLECTION.DOWNLOAD}${sourceID}`;
},
},
diff --git a/src/components/AnchorForAttachmentsOnly/anchorForAttachmentsOnlyPropTypes.js b/src/components/AnchorForAttachmentsOnly/anchorForAttachmentsOnlyPropTypes.js
deleted file mode 100644
index 9452e615d31c..000000000000
--- a/src/components/AnchorForAttachmentsOnly/anchorForAttachmentsOnlyPropTypes.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import PropTypes from 'prop-types';
-import stylePropTypes from '@styles/stylePropTypes';
-
-const propTypes = {
- /** The URL of the attachment */
- source: PropTypes.string,
-
- /** Filename for attachments. */
- displayName: PropTypes.string,
-
- /** Any additional styles to apply */
- style: stylePropTypes,
-};
-
-const defaultProps = {
- source: '',
- style: {},
- displayName: '',
-};
-
-export {propTypes, defaultProps};
diff --git a/src/components/AnchorForAttachmentsOnly/index.native.js b/src/components/AnchorForAttachmentsOnly/index.native.tsx
similarity index 62%
rename from src/components/AnchorForAttachmentsOnly/index.native.js
rename to src/components/AnchorForAttachmentsOnly/index.native.tsx
index 3277d51ec058..2e0e94bc0b88 100644
--- a/src/components/AnchorForAttachmentsOnly/index.native.js
+++ b/src/components/AnchorForAttachmentsOnly/index.native.tsx
@@ -1,9 +1,9 @@
import React from 'react';
import useThemeStyles from '@hooks/useThemeStyles';
-import * as anchorForAttachmentsOnlyPropTypes from './anchorForAttachmentsOnlyPropTypes';
import BaseAnchorForAttachmentsOnly from './BaseAnchorForAttachmentsOnly';
+import type AnchorForAttachmentsOnlyProps from './types';
-function AnchorForAttachmentsOnly(props) {
+function AnchorForAttachmentsOnly(props: AnchorForAttachmentsOnlyProps) {
const styles = useThemeStyles();
return (
;
+};
+
+export default AnchorForAttachmentsOnlyProps;
diff --git a/src/components/AttachmentModal.js b/src/components/AttachmentModal.js
index d24d1e18907f..bd8d535e540f 100755
--- a/src/components/AttachmentModal.js
+++ b/src/components/AttachmentModal.js
@@ -19,7 +19,6 @@ import fileDownload from '@libs/fileDownload';
import * as FileUtils from '@libs/fileDownload/FileUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
-import * as ReportUtils from '@libs/ReportUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import useNativeDriver from '@libs/useNativeDriver';
import reportPropTypes from '@pages/reportPropTypes';
@@ -95,6 +94,9 @@ const propTypes = {
/** Whether it is a receipt attachment or not */
isReceiptAttachment: PropTypes.bool,
+
+ /** Whether the receipt can be replaced */
+ canEditReceipt: PropTypes.bool,
};
const defaultProps = {
@@ -113,6 +115,7 @@ const defaultProps = {
onCarouselAttachmentChange: () => {},
isWorkspaceAvatar: false,
isReceiptAttachment: false,
+ canEditReceipt: false,
};
function AttachmentModal(props) {
@@ -126,7 +129,7 @@ function AttachmentModal(props) {
const [isAuthTokenRequired, setIsAuthTokenRequired] = useState(props.isAuthTokenRequired);
const [attachmentInvalidReasonTitle, setAttachmentInvalidReasonTitle] = useState('');
const [attachmentInvalidReason, setAttachmentInvalidReason] = useState(null);
- const [source, setSource] = useState(props.source);
+ const [source, setSource] = useState(() => props.source);
const [modalType, setModalType] = useState(CONST.MODAL.MODAL_TYPE.CENTERED_UNSWIPEABLE);
const [isConfirmButtonDisabled, setIsConfirmButtonDisabled] = useState(false);
const [confirmButtonFadeAnimation] = useState(() => new Animated.Value(1));
@@ -359,7 +362,7 @@ function AttachmentModal(props) {
}, []);
useEffect(() => {
- setSource(props.source);
+ setSource(() => props.source);
}, [props.source]);
useEffect(() => {
@@ -372,28 +375,34 @@ function AttachmentModal(props) {
if (!props.isReceiptAttachment || !props.parentReport || !props.parentReportActions) {
return [];
}
- const menuItems = [];
- const parentReportAction = props.parentReportActions[props.report.parentReportActionID];
- const canEdit =
- ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, props.parentReport.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT, props.transaction) &&
- !TransactionUtils.isDistanceRequest(props.transaction);
- if (canEdit) {
+ const menuItems = [];
+ if (props.canEditReceipt) {
menuItems.push({
icon: Expensicons.Camera,
text: props.translate('common.replace'),
onSelected: () => {
closeModal();
- Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(props.report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT));
+ Navigation.navigate(
+ ROUTES.MONEY_REQUEST_STEP_SCAN.getRoute(
+ CONST.IOU.ACTION.EDIT,
+ CONST.IOU.TYPE.REQUEST,
+ props.transaction.transactionID,
+ props.report.reportID,
+ Navigation.getActiveRouteWithoutParams(),
+ ),
+ );
},
});
}
- menuItems.push({
- icon: Expensicons.Download,
- text: props.translate('common.download'),
- onSelected: () => downloadAttachment(source),
- });
- if (TransactionUtils.hasReceipt(props.transaction) && !TransactionUtils.isReceiptBeingScanned(props.transaction) && canEdit) {
+ if (!isOffline) {
+ menuItems.push({
+ icon: Expensicons.Download,
+ text: props.translate('common.download'),
+ onSelected: () => downloadAttachment(source),
+ });
+ }
+ if (TransactionUtils.hasReceipt(props.transaction) && !TransactionUtils.isReceiptBeingScanned(props.transaction) && props.canEditReceipt) {
menuItems.push({
icon: Expensicons.Trashcan,
text: props.translate('receipt.deleteReceipt'),
@@ -414,7 +423,7 @@ function AttachmentModal(props) {
if (!_.isEmpty(props.report)) {
headerTitle = translate(props.isReceiptAttachment ? 'common.receipt' : 'common.attachment');
shouldShowDownloadButton = props.allowDownload && isDownloadButtonReadyToBeShown && !props.isReceiptAttachment && !isOffline;
- shouldShowThreeDotsButton = props.isReceiptAttachment && isModalOpen;
+ shouldShowThreeDotsButton = props.isReceiptAttachment && isModalOpen && threeDotsMenuItems.length !== 0;
}
return (
diff --git a/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.android.js b/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.android.js
index 6d510d234512..db4f4f11d68c 100644
--- a/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.android.js
+++ b/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.android.js
@@ -15,17 +15,26 @@ function AttachmentViewPdf(props) {
const offsetX = useSharedValue(0);
const offsetY = useSharedValue(0);
+ // Reanimated freezes all objects captured in the closure of a worklet.
+ // Since Reanimated 3, entire objects are captured instead of just the relevant properties.
+ // See https://github.com/software-mansion/react-native-reanimated/pull/4060
+ // Because context contains more properties, all of them (most notably the pager ref) were
+ // frozen, which combined with Reanimated using strict mode since 3.6.0 was resulting in errors.
+ // Without strict mode, it would just silently fail.
+ // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze#description
+ const shouldPagerScroll = attachmentCarouselPagerContext !== null ? attachmentCarouselPagerContext.shouldPagerScroll : undefined;
+
const Pan = Gesture.Pan()
.manualActivation(true)
.onTouchesMove((evt) => {
- if (offsetX.value !== 0 && offsetY.value !== 0 && attachmentCarouselPagerContext) {
+ if (offsetX.value !== 0 && offsetY.value !== 0 && shouldPagerScroll) {
// if the value of X is greater than Y and the pdf is not zoomed in,
// enable the pager scroll so that the user
// can swipe to the next attachment otherwise disable it.
if (Math.abs(evt.allTouches[0].absoluteX - offsetX.value) > Math.abs(evt.allTouches[0].absoluteY - offsetY.value) && scaleRef.value === 1) {
- attachmentCarouselPagerContext.shouldPagerScroll.value = true;
+ shouldPagerScroll.value = true;
} else {
- attachmentCarouselPagerContext.shouldPagerScroll.value = false;
+ shouldPagerScroll.value = false;
}
}
offsetX.value = evt.allTouches[0].absoluteX;
diff --git a/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.tsx b/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.tsx
index fc3bf4659bd7..5da9c6981603 100644
--- a/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.tsx
+++ b/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.tsx
@@ -107,7 +107,7 @@ function BaseAutoCompleteSuggestions(
keyExtractor={keyExtractor}
removeClippedSubviews={false}
showsVerticalScrollIndicator={innerHeight > rowHeight.value}
- extraData={highlightedSuggestionIndex}
+ extraData={[highlightedSuggestionIndex, renderSuggestionMenuItem]}
/>
diff --git a/src/components/AvatarCropModal/ImageCropView.js b/src/components/AvatarCropModal/ImageCropView.js
index ff91a654f5dd..92cbe3a4da04 100644
--- a/src/components/AvatarCropModal/ImageCropView.js
+++ b/src/components/AvatarCropModal/ImageCropView.js
@@ -90,7 +90,7 @@ function ImageCropView(props) {
diff --git a/src/components/AvatarWithDisplayName.tsx b/src/components/AvatarWithDisplayName.tsx
index 4580f3b7e4d4..e9e1054427b9 100644
--- a/src/components/AvatarWithDisplayName.tsx
+++ b/src/components/AvatarWithDisplayName.tsx
@@ -141,6 +141,7 @@ function AvatarWithDisplayName({
)}
{!!subtitle && (
diff --git a/src/components/BaseMiniContextMenuItem.tsx b/src/components/BaseMiniContextMenuItem.tsx
index 1f9a14cdfdee..7bed44cd8f13 100644
--- a/src/components/BaseMiniContextMenuItem.tsx
+++ b/src/components/BaseMiniContextMenuItem.tsx
@@ -8,6 +8,7 @@ import DomUtils from '@libs/DomUtils';
import getButtonState from '@libs/getButtonState';
import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager';
import variables from '@styles/variables';
+import CONST from '@src/CONST';
import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
import Tooltip from './Tooltip/PopoverAnchorTooltip';
@@ -66,6 +67,7 @@ function BaseMiniContextMenuItem({tooltipText, onPress, children, isDelayButtonS
event.preventDefault();
}}
accessibilityLabel={tooltipText}
+ role={CONST.ROLE.BUTTON}
style={({hovered, pressed}) => [
styles.reportActionContextMenuMiniButton,
StyleUtils.getButtonBackgroundColorStyle(getButtonState(hovered, pressed, isDelayButtonStateComplete)),
diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx
index dd0499d4d243..5fb134648134 100644
--- a/src/components/Button/index.tsx
+++ b/src/components/Button/index.tsx
@@ -1,6 +1,6 @@
import {useIsFocused} from '@react-navigation/native';
import type {ForwardedRef} from 'react';
-import React, {useCallback} from 'react';
+import React, {useCallback, useMemo} from 'react';
import type {GestureResponderEvent, StyleProp, TextStyle, ViewStyle} from 'react-native';
import {ActivityIndicator, View} from 'react-native';
import Icon from '@components/Icon';
@@ -8,7 +8,7 @@ import * as Expensicons from '@components/Icon/Expensicons';
import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
import Text from '@components/Text';
import withNavigationFallback from '@components/withNavigationFallback';
-import useActiveElement from '@hooks/useActiveElement';
+import useActiveElementRole from '@hooks/useActiveElementRole';
import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
@@ -118,6 +118,44 @@ type ButtonProps = (ButtonWithText | ChildrenProps) & {
accessibilityLabel?: string;
};
+type KeyboardShortcutComponentProps = Pick;
+
+const accessibilityRoles: string[] = Object.values(CONST.ACCESSIBILITY_ROLE);
+
+function KeyboardShortcutComponent({isDisabled = false, isLoading = false, onPress = () => {}, pressOnEnter, allowBubble, enterKeyEventListenerPriority}: KeyboardShortcutComponentProps) {
+ const isFocused = useIsFocused();
+ const activeElementRole = useActiveElementRole();
+
+ const shouldDisableEnterShortcut = useMemo(() => accessibilityRoles.includes(activeElementRole ?? '') && activeElementRole !== CONST.ACCESSIBILITY_ROLE.TEXT, [activeElementRole]);
+
+ const keyboardShortcutCallback = useCallback(
+ (event?: GestureResponderEvent | KeyboardEvent) => {
+ if (!validateSubmitShortcut(isDisabled, isLoading, event)) {
+ return;
+ }
+ onPress();
+ },
+ [isDisabled, isLoading, onPress],
+ );
+
+ const config = useMemo(
+ () => ({
+ isActive: pressOnEnter && !shouldDisableEnterShortcut && isFocused,
+ shouldBubble: allowBubble,
+ priority: enterKeyEventListenerPriority,
+ shouldPreventDefault: false,
+ }),
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ [shouldDisableEnterShortcut, isFocused],
+ );
+
+ useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ENTER, keyboardShortcutCallback, config);
+
+ return null;
+}
+
+KeyboardShortcutComponent.displayName = 'KeyboardShortcutComponent';
+
function Button(
{
allowBubble = false,
@@ -164,27 +202,6 @@ function Button(
) {
const theme = useTheme();
const styles = useThemeStyles();
- const isFocused = useIsFocused();
- const activeElement = useActiveElement();
- const accessibilityRoles: string[] = Object.values(CONST.ACCESSIBILITY_ROLE);
- const shouldDisableEnterShortcut = accessibilityRoles.includes(activeElement?.role ?? '') && activeElement?.role !== CONST.ACCESSIBILITY_ROLE.TEXT;
-
- const keyboardShortcutCallback = useCallback(
- (event?: GestureResponderEvent | KeyboardEvent) => {
- if (!validateSubmitShortcut(isFocused, isDisabled, isLoading, event)) {
- return;
- }
- onPress();
- },
- [isDisabled, isFocused, isLoading, onPress],
- );
-
- useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ENTER, keyboardShortcutCallback, {
- isActive: pressOnEnter && !shouldDisableEnterShortcut,
- shouldBubble: allowBubble,
- priority: enterKeyEventListenerPriority,
- shouldPreventDefault: false,
- });
const renderContent = () => {
if ('children' in rest) {
@@ -247,72 +264,82 @@ function Button(
};
return (
- {
- if (event?.type === 'click') {
- const currentTarget = event?.currentTarget as HTMLElement;
- currentTarget?.blur();
- }
-
- if (shouldEnableHapticFeedback) {
- HapticFeedback.press();
- }
- return onPress(event);
- }}
- onLongPress={(event) => {
- if (isLongPressDisabled) {
- return;
- }
- if (shouldEnableHapticFeedback) {
- HapticFeedback.longPress();
- }
- onLongPress(event);
- }}
- onPressIn={onPressIn}
- onPressOut={onPressOut}
- onMouseDown={onMouseDown}
- disabled={isLoading || isDisabled}
- wrapperStyle={[
- isDisabled ? {...styles.cursorDisabled, ...styles.noSelect} : {},
- styles.buttonContainer,
- shouldRemoveRightBorderRadius ? styles.noRightBorderRadius : undefined,
- shouldRemoveLeftBorderRadius ? styles.noLeftBorderRadius : undefined,
- style,
- ]}
- style={[
- styles.button,
- small ? styles.buttonSmall : undefined,
- medium ? styles.buttonMedium : undefined,
- large ? styles.buttonLarge : undefined,
- success ? styles.buttonSuccess : undefined,
- danger ? styles.buttonDanger : undefined,
- isDisabled && (success || danger) ? styles.buttonOpacityDisabled : undefined,
- isDisabled && !danger && !success ? styles.buttonDisabled : undefined,
- shouldRemoveRightBorderRadius ? styles.noRightBorderRadius : undefined,
- shouldRemoveLeftBorderRadius ? styles.noLeftBorderRadius : undefined,
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
- 'text' in rest && (rest?.icon || rest?.shouldShowRightIcon) ? styles.alignItemsStretch : undefined,
- innerStyles,
- ]}
- hoverStyle={[
- shouldUseDefaultHover && !isDisabled ? styles.buttonDefaultHovered : undefined,
- success && !isDisabled ? styles.buttonSuccessHovered : undefined,
- danger && !isDisabled ? styles.buttonDangerHovered : undefined,
- ]}
- id={id}
- accessibilityLabel={accessibilityLabel}
- role={CONST.ROLE.BUTTON}
- hoverDimmingValue={1}
- >
- {renderContent()}
- {isLoading && (
-
- )}
-
+ <>
+
+ {
+ if (event?.type === 'click') {
+ const currentTarget = event?.currentTarget as HTMLElement;
+ currentTarget?.blur();
+ }
+
+ if (shouldEnableHapticFeedback) {
+ HapticFeedback.press();
+ }
+ return onPress(event);
+ }}
+ onLongPress={(event) => {
+ if (isLongPressDisabled) {
+ return;
+ }
+ if (shouldEnableHapticFeedback) {
+ HapticFeedback.longPress();
+ }
+ onLongPress(event);
+ }}
+ onPressIn={onPressIn}
+ onPressOut={onPressOut}
+ onMouseDown={onMouseDown}
+ disabled={isLoading || isDisabled}
+ wrapperStyle={[
+ isDisabled ? {...styles.cursorDisabled, ...styles.noSelect} : {},
+ styles.buttonContainer,
+ shouldRemoveRightBorderRadius ? styles.noRightBorderRadius : undefined,
+ shouldRemoveLeftBorderRadius ? styles.noLeftBorderRadius : undefined,
+ style,
+ ]}
+ style={[
+ styles.button,
+ small ? styles.buttonSmall : undefined,
+ medium ? styles.buttonMedium : undefined,
+ large ? styles.buttonLarge : undefined,
+ success ? styles.buttonSuccess : undefined,
+ danger ? styles.buttonDanger : undefined,
+ isDisabled && (success || danger) ? styles.buttonOpacityDisabled : undefined,
+ isDisabled && !danger && !success ? styles.buttonDisabled : undefined,
+ shouldRemoveRightBorderRadius ? styles.noRightBorderRadius : undefined,
+ shouldRemoveLeftBorderRadius ? styles.noLeftBorderRadius : undefined,
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
+ 'text' in rest && (rest?.icon || rest?.shouldShowRightIcon) ? styles.alignItemsStretch : undefined,
+ innerStyles,
+ ]}
+ hoverStyle={[
+ shouldUseDefaultHover && !isDisabled ? styles.buttonDefaultHovered : undefined,
+ success && !isDisabled ? styles.buttonSuccessHovered : undefined,
+ danger && !isDisabled ? styles.buttonDangerHovered : undefined,
+ ]}
+ id={id}
+ accessibilityLabel={accessibilityLabel}
+ role={CONST.ROLE.BUTTON}
+ hoverDimmingValue={1}
+ >
+ {renderContent()}
+ {isLoading && (
+
+ )}
+
+ >
);
}
diff --git a/src/components/Button/validateSubmitShortcut/index.native.ts b/src/components/Button/validateSubmitShortcut/index.native.ts
index 3f277ed208a1..4602b40c832f 100644
--- a/src/components/Button/validateSubmitShortcut/index.native.ts
+++ b/src/components/Button/validateSubmitShortcut/index.native.ts
@@ -3,14 +3,13 @@ import type ValidateSubmitShortcut from './types';
/**
* Validate if the submit shortcut should be triggered depending on the button state
*
- * @param isFocused Whether Button is on active screen
* @param isDisabled Indicates whether the button should be disabled
* @param isLoading Indicates whether the button should be disabled and in the loading state
* @return Returns `true` if the shortcut should be triggered
*/
-const validateSubmitShortcut: ValidateSubmitShortcut = (isFocused, isDisabled, isLoading) => {
- if (!isFocused || isDisabled || isLoading) {
+const validateSubmitShortcut: ValidateSubmitShortcut = (isDisabled, isLoading) => {
+ if (isDisabled || isLoading) {
return false;
}
diff --git a/src/components/Button/validateSubmitShortcut/index.ts b/src/components/Button/validateSubmitShortcut/index.ts
index 695c56af7bb7..f8cea44f73d6 100644
--- a/src/components/Button/validateSubmitShortcut/index.ts
+++ b/src/components/Button/validateSubmitShortcut/index.ts
@@ -3,16 +3,15 @@ import type ValidateSubmitShortcut from './types';
/**
* Validate if the submit shortcut should be triggered depending on the button state
*
- * @param isFocused Whether Button is on active screen
* @param isDisabled Indicates whether the button should be disabled
* @param isLoading Indicates whether the button should be disabled and in the loading state
* @param event Focused input event
* @returns Returns `true` if the shortcut should be triggered
*/
-const validateSubmitShortcut: ValidateSubmitShortcut = (isFocused, isDisabled, isLoading, event) => {
+const validateSubmitShortcut: ValidateSubmitShortcut = (isDisabled, isLoading, event) => {
const eventTarget = event?.target as HTMLElement;
- if (!isFocused || isDisabled || isLoading || eventTarget.nodeName === 'TEXTAREA') {
+ if (isDisabled || isLoading || eventTarget.nodeName === 'TEXTAREA') {
return false;
}
diff --git a/src/components/Button/validateSubmitShortcut/types.ts b/src/components/Button/validateSubmitShortcut/types.ts
index 088718d0334e..d1ff24fb0510 100644
--- a/src/components/Button/validateSubmitShortcut/types.ts
+++ b/src/components/Button/validateSubmitShortcut/types.ts
@@ -1,5 +1,5 @@
import type {GestureResponderEvent} from 'react-native';
-type ValidateSubmitShortcut = (isFocused: boolean, isDisabled: boolean, isLoading: boolean, event?: GestureResponderEvent | KeyboardEvent) => boolean;
+type ValidateSubmitShortcut = (isDisabled: boolean, isLoading: boolean, event?: GestureResponderEvent | KeyboardEvent) => boolean;
export default ValidateSubmitShortcut;
diff --git a/src/components/CheckboxWithLabel.tsx b/src/components/CheckboxWithLabel.tsx
index a25ccf184f52..602fb154deba 100644
--- a/src/components/CheckboxWithLabel.tsx
+++ b/src/components/CheckboxWithLabel.tsx
@@ -42,7 +42,7 @@ type CheckboxWithLabelProps = RequiredLabelProps & {
/** Error text to display */
errorText?: string;
- /** Value for checkbox. This prop is intended to be set by Form.js only */
+ /** Value for checkbox. This prop is intended to be set by FormProvider only */
value?: boolean;
/** The default value for the checkbox */
diff --git a/src/components/Composer/types.ts b/src/components/Composer/types.ts
index bfdcb6715d40..d8d88970ea78 100644
--- a/src/components/Composer/types.ts
+++ b/src/components/Composer/types.ts
@@ -6,6 +6,12 @@ type TextSelection = {
};
type ComposerProps = {
+ /** identify id in the text input */
+ id?: string;
+
+ /** Indicate whether input is multiline */
+ multiline?: boolean;
+
/** Maximum number of lines in the text input */
maxLines?: number;
@@ -18,6 +24,9 @@ type ComposerProps = {
/** Number of lines for the comment */
numberOfLines?: number;
+ /** Callback method handle when the input is changed */
+ onChangeText?: (numberOfLines: string) => void;
+
/** Callback method to update number of lines for the comment */
onNumberOfLinesChange?: (numberOfLines: number) => void;
@@ -69,6 +78,8 @@ type ComposerProps = {
onFocus?: (event: NativeSyntheticEvent) => void;
+ onBlur?: (event: NativeSyntheticEvent) => void;
+
/** Should make the input only scroll inside the element avoid scroll out to parent */
shouldContainScroll?: boolean;
};
diff --git a/src/components/ConfirmPopover.js b/src/components/ConfirmPopover.js
deleted file mode 100644
index 83001736b471..000000000000
--- a/src/components/ConfirmPopover.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import ConfirmContent from './ConfirmContent';
-import Popover from './Popover';
-import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions';
-
-const propTypes = {
- /** Title of the modal */
- title: PropTypes.string.isRequired,
-
- /** A callback to call when the form has been submitted */
- onConfirm: PropTypes.func.isRequired,
-
- /** A callback to call when the form has been closed */
- onCancel: PropTypes.func,
-
- /** Modal visibility */
- isVisible: PropTypes.bool.isRequired,
-
- /** Confirm button text */
- confirmText: PropTypes.string,
-
- /** Cancel button text */
- cancelText: PropTypes.string,
-
- /** Is the action destructive */
- danger: PropTypes.bool,
-
- /** Whether we should show the cancel button */
- shouldShowCancelButton: PropTypes.bool,
-
- /** Modal content text/element */
- prompt: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
-
- /** Where the popover should be positioned */
- anchorPosition: PropTypes.shape({
- top: PropTypes.number,
- left: PropTypes.number,
- }).isRequired,
-
- /** Styles for view */
- // eslint-disable-next-line react/forbid-prop-types
- contentStyles: PropTypes.arrayOf(PropTypes.object),
-
- ...windowDimensionsPropTypes,
-};
-
-const defaultProps = {
- confirmText: '',
- cancelText: '',
- danger: false,
- onCancel: () => {},
- shouldShowCancelButton: true,
- prompt: '',
- contentStyles: [],
-};
-
-function ConfirmPopover(props) {
- return (
-
-
-
- );
-}
-
-ConfirmPopover.propTypes = propTypes;
-ConfirmPopover.defaultProps = defaultProps;
-ConfirmPopover.displayName = 'ConfirmPopover';
-export default withWindowDimensions(ConfirmPopover);
diff --git a/src/components/ConfirmedRoute.js b/src/components/ConfirmedRoute.tsx
similarity index 61%
rename from src/components/ConfirmedRoute.js
rename to src/components/ConfirmedRoute.tsx
index 466666dd9ef6..c01f7c6250f4 100644
--- a/src/components/ConfirmedRoute.js
+++ b/src/components/ConfirmedRoute.tsx
@@ -1,9 +1,7 @@
-import lodashGet from 'lodash/get';
-import lodashIsNil from 'lodash/isNil';
-import PropTypes from 'prop-types';
import React, {useCallback, useEffect} from 'react';
+import type {ReactNode} from 'react';
import {withOnyx} from 'react-native-onyx';
-import _ from 'underscore';
+import type {OnyxEntry} from 'react-native-onyx/lib/types';
import useNetwork from '@hooks/useNetwork';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
@@ -11,54 +9,51 @@ import * as TransactionUtils from '@libs/TransactionUtils';
import * as MapboxToken from '@userActions/MapboxToken';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
+import type {MapboxAccessToken, Transaction} from '@src/types/onyx';
+import type {WaypointCollection} from '@src/types/onyx/Transaction';
+import type IconAsset from '@src/types/utils/IconAsset';
import DistanceMapView from './DistanceMapView';
import * as Expensicons from './Icon/Expensicons';
import ImageSVG from './ImageSVG';
import PendingMapView from './MapView/PendingMapView';
-import transactionPropTypes from './transactionPropTypes';
-const propTypes = {
- /** Transaction that stores the distance request data */
- transaction: transactionPropTypes,
+type WayPoint = {
+ id: string;
+ coordinate: [number, number];
+ markerComponent: () => ReactNode;
+};
+type ConfirmedRoutePropsOnyxProps = {
/** Data about Mapbox token for calling Mapbox API */
- mapboxAccessToken: PropTypes.shape({
- /** Temporary token for Mapbox API */
- token: PropTypes.string,
-
- /** Time when the token will expire in ISO 8601 */
- expiration: PropTypes.string,
- }),
+ mapboxAccessToken: OnyxEntry;
};
-const defaultProps = {
- transaction: {},
- mapboxAccessToken: {
- token: '',
- },
+type ConfirmedRouteProps = ConfirmedRoutePropsOnyxProps & {
+ /** Transaction that stores the distance request data */
+ transaction: Transaction;
};
-function ConfirmedRoute({mapboxAccessToken, transaction}) {
+function ConfirmedRoute({mapboxAccessToken, transaction}: ConfirmedRouteProps) {
const {isOffline} = useNetwork();
- const {route0: route} = transaction.routes || {};
- const waypoints = lodashGet(transaction, 'comment.waypoints', {});
- const coordinates = lodashGet(route, 'geometry.coordinates', []);
+ const {route0: route} = transaction.routes ?? {};
+ const waypoints = transaction.comment?.waypoints ?? {};
+ const coordinates = route?.geometry?.coordinates ?? [];
const theme = useTheme();
const styles = useThemeStyles();
const getWaypointMarkers = useCallback(
- (waypointsData) => {
- const numberOfWaypoints = _.size(waypointsData);
+ (waypointsData: WaypointCollection): WayPoint[] => {
+ const numberOfWaypoints = Object.keys(waypointsData).length;
const lastWaypointIndex = numberOfWaypoints - 1;
- return _.filter(
- _.map(waypointsData, (waypoint, key) => {
- if (!waypoint || lodashIsNil(waypoint.lat) || lodashIsNil(waypoint.lng)) {
+ return Object.entries(waypointsData)
+ .map(([key, waypoint]) => {
+ if (!waypoint?.lat || !waypoint?.lng) {
return;
}
const index = TransactionUtils.getWaypointIndex(key);
- let MarkerComponent;
+ let MarkerComponent: IconAsset;
if (index === 0) {
MarkerComponent = Expensicons.DotIndicatorUnfilled;
} else if (index === lastWaypointIndex) {
@@ -69,8 +64,8 @@ function ConfirmedRoute({mapboxAccessToken, transaction}) {
return {
id: `${waypoint.lng},${waypoint.lat},${index}`,
- coordinate: [waypoint.lng, waypoint.lat],
- markerComponent: () => (
+ coordinate: [waypoint.lng, waypoint.lat] as const,
+ markerComponent: (): ReactNode => (
),
};
- }),
- (waypoint) => waypoint,
- );
+ })
+ .filter((waypoint): waypoint is WayPoint => !!waypoint);
},
[theme],
);
@@ -95,16 +89,16 @@ function ConfirmedRoute({mapboxAccessToken, transaction}) {
return (
<>
- {!isOffline && Boolean(mapboxAccessToken.token) ? (
+ {!isOffline && Boolean(mapboxAccessToken?.token) ? (
}
style={[styles.mapView, styles.br4]}
waypoints={waypointMarkers}
styleURL={CONST.MAPBOX.STYLE_URL}
@@ -116,12 +110,10 @@ function ConfirmedRoute({mapboxAccessToken, transaction}) {
);
}
-export default withOnyx({
+export default withOnyx({
mapboxAccessToken: {
key: ONYXKEYS.MAPBOX_ACCESS_TOKEN,
},
})(ConfirmedRoute);
ConfirmedRoute.displayName = 'ConfirmedRoute';
-ConfirmedRoute.propTypes = propTypes;
-ConfirmedRoute.defaultProps = defaultProps;
diff --git a/src/components/ContextMenuItem.js b/src/components/ContextMenuItem.tsx
similarity index 67%
rename from src/components/ContextMenuItem.js
rename to src/components/ContextMenuItem.tsx
index e7d2bda3a667..781d2f718bcf 100644
--- a/src/components/ContextMenuItem.js
+++ b/src/components/ContextMenuItem.tsx
@@ -1,58 +1,52 @@
-import PropTypes from 'prop-types';
+import type {ForwardedRef} from 'react';
import React, {forwardRef, useImperativeHandle} from 'react';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import useThrottledButtonState from '@hooks/useThrottledButtonState';
import useWindowDimensions from '@hooks/useWindowDimensions';
import getButtonState from '@libs/getButtonState';
+import type IconAsset from '@src/types/utils/IconAsset';
import BaseMiniContextMenuItem from './BaseMiniContextMenuItem';
import Icon from './Icon';
-import sourcePropTypes from './Image/sourcePropTypes';
import MenuItem from './MenuItem';
-const propTypes = {
+type ContextMenuItemProps = {
/** Icon Component */
- icon: sourcePropTypes.isRequired,
+ icon: IconAsset;
/** Text to display */
- text: PropTypes.string.isRequired,
+ text: string;
/** Icon to show when interaction was successful */
- successIcon: sourcePropTypes,
+ successIcon?: IconAsset;
/** Text to show when interaction was successful */
- successText: PropTypes.string,
+ successText?: string;
/** Whether to show the mini menu */
- isMini: PropTypes.bool,
+ isMini?: boolean;
/** Callback to fire when the item is pressed */
- onPress: PropTypes.func.isRequired,
+ onPress: () => void;
/** A description text to show under the title */
- description: PropTypes.string,
+ description?: string;
/** The action accept for anonymous user or not */
- isAnonymousAction: PropTypes.bool,
+ isAnonymousAction?: boolean;
/** Whether the menu item is focused or not */
- isFocused: PropTypes.bool,
-
- /** Forwarded ref to ContextMenuItem */
- innerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
+ isFocused?: boolean;
};
-const defaultProps = {
- isMini: false,
- successIcon: null,
- successText: '',
- description: '',
- isAnonymousAction: false,
- isFocused: false,
- innerRef: null,
+type ContextMenuItemHandle = {
+ triggerPressAndUpdateSuccess?: () => void;
};
-function ContextMenuItem({onPress, successIcon, successText, icon, text, isMini, description, isAnonymousAction, isFocused, innerRef}) {
+function ContextMenuItem(
+ {onPress, successIcon, successText = '', icon, text, isMini = false, description = '', isAnonymousAction = false, isFocused = false}: ContextMenuItemProps,
+ ref: ForwardedRef,
+) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const {windowWidth} = useWindowDimensions();
@@ -66,12 +60,12 @@ function ContextMenuItem({onPress, successIcon, successText, icon, text, isMini,
// We only set the success state when we have icon or text to represent the success state
// We may want to replace this check by checking the Result from OnPress Callback in future.
- if (successIcon || successText) {
+ if (!!successIcon || successText) {
setThrottledButtonInactive();
}
};
- useImperativeHandle(innerRef, () => ({triggerPressAndUpdateSuccess}));
+ useImperativeHandle(ref, () => ({triggerPressAndUpdateSuccess}));
const itemIcon = !isThrottledButtonActive && successIcon ? successIcon : icon;
const itemText = !isThrottledButtonActive && successText ? successText : text;
@@ -107,18 +101,6 @@ function ContextMenuItem({onPress, successIcon, successText, icon, text, isMini,
);
}
-ContextMenuItem.propTypes = propTypes;
-ContextMenuItem.defaultProps = defaultProps;
ContextMenuItem.displayName = 'ContextMenuItem';
-const ContextMenuItemWithRef = forwardRef((props, ref) => (
-
-));
-
-ContextMenuItemWithRef.displayName = 'ContextMenuItemWithRef';
-
-export default ContextMenuItemWithRef;
+export default forwardRef(ContextMenuItem);
diff --git a/src/components/DatePicker/CalendarPicker/index.js b/src/components/DatePicker/CalendarPicker/index.js
index 571ddc820d43..f10af5e4a5a7 100644
--- a/src/components/DatePicker/CalendarPicker/index.js
+++ b/src/components/DatePicker/CalendarPicker/index.js
@@ -112,14 +112,44 @@ class CalendarPicker extends React.PureComponent {
* Handles the user pressing the previous month arrow of the calendar picker.
*/
moveToPrevMonth() {
- this.setState((prev) => ({currentDateView: subMonths(new Date(prev.currentDateView), 1)}));
+ this.setState((prev) => {
+ const prevMonth = subMonths(new Date(prev.currentDateView), 1);
+ // if year is subtracted, we need to update the years list
+ let newYears = prev.years;
+ if (prevMonth.getFullYear() < prev.currentDateView.getFullYear()) {
+ newYears = _.map(prev.years, (item) => ({
+ ...item,
+ isSelected: item.value === prevMonth.getFullYear(),
+ }));
+ }
+
+ return {
+ currentDateView: prevMonth,
+ years: newYears,
+ };
+ });
}
/**
* Handles the user pressing the next month arrow of the calendar picker.
*/
moveToNextMonth() {
- this.setState((prev) => ({currentDateView: addMonths(new Date(prev.currentDateView), 1)}));
+ this.setState((prev) => {
+ const nextMonth = addMonths(new Date(prev.currentDateView), 1);
+ // if year is added, we need to update the years list
+ let newYears = prev.years;
+ if (nextMonth.getFullYear() > prev.currentDateView.getFullYear()) {
+ newYears = _.map(prev.years, (item) => ({
+ ...item,
+ isSelected: item.value === nextMonth.getFullYear(),
+ }));
+ }
+
+ return {
+ currentDateView: nextMonth,
+ years: newYears,
+ };
+ });
}
render() {
diff --git a/src/components/DeeplinkWrapper/DeeplinkRedirectLoadingIndicator.tsx b/src/components/DeeplinkWrapper/DeeplinkRedirectLoadingIndicator.tsx
index 27d8027bbcff..ed91b51a2a44 100644
--- a/src/components/DeeplinkWrapper/DeeplinkRedirectLoadingIndicator.tsx
+++ b/src/components/DeeplinkWrapper/DeeplinkRedirectLoadingIndicator.tsx
@@ -37,7 +37,6 @@ function DeeplinkRedirectLoadingIndicator({openLinkInBrowser, session}: Deeplink
diff --git a/src/components/DisplayNames/DisplayNamesWithTooltip.tsx b/src/components/DisplayNames/DisplayNamesWithTooltip.tsx
index f22b1f0c2209..0d554baabeda 100644
--- a/src/components/DisplayNames/DisplayNamesWithTooltip.tsx
+++ b/src/components/DisplayNames/DisplayNamesWithTooltip.tsx
@@ -4,6 +4,7 @@ import {View} from 'react-native';
import Text from '@components/Text';
import Tooltip from '@components/Tooltip';
import useThemeStyles from '@hooks/useThemeStyles';
+import * as ReportUtils from '@libs/ReportUtils';
import DisplayNamesTooltipItem from './DisplayNamesTooltipItem';
import type DisplayNamesProps from './types';
@@ -48,12 +49,12 @@ function DisplayNamesWithToolTip({shouldUseFullTitle, fullTitle, displayNamesWit
return (
// Tokenization of string only support prop numberOfLines on Web
{shouldUseFullTitle
- ? fullTitle
+ ? ReportUtils.formatReportLastMessageText(fullTitle)
: displayNamesWithTooltips.map(({displayName, accountID, avatar, login}, index) => (
// eslint-disable-next-line react/no-array-index-key
diff --git a/src/components/DistanceRequest/index.js b/src/components/DistanceRequest/index.js
index 72be7c2b8873..b63ce337a1d9 100644
--- a/src/components/DistanceRequest/index.js
+++ b/src/components/DistanceRequest/index.js
@@ -24,6 +24,7 @@ import variables from '@styles/variables';
import * as MapboxToken from '@userActions/MapboxToken';
import * as Transaction from '@userActions/Transaction';
import * as TransactionEdit from '@userActions/TransactionEdit';
+import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import DistanceRequestFooter from './DistanceRequestFooter';
@@ -170,7 +171,9 @@ function DistanceRequest({transactionID, report, transaction, route, isEditingRe
* @param {Number} index of the waypoint to edit
*/
const navigateToWaypointEditPage = (index) => {
- Navigation.navigate(isEditingRequest ? ROUTES.MONEY_REQUEST_EDIT_WAYPOINT.getRoute(report.reportID, transactionID, index) : ROUTES.MONEY_REQUEST_WAYPOINT.getRoute('request', index));
+ Navigation.navigate(
+ ROUTES.MONEY_REQUEST_STEP_WAYPOINT.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.REQUEST, transactionID, report.reportID, index, Navigation.getActiveRouteWithoutParams()),
+ );
};
const getError = () => {
diff --git a/src/components/EReceiptThumbnail.js b/src/components/EReceiptThumbnail.tsx
similarity index 74%
rename from src/components/EReceiptThumbnail.js
rename to src/components/EReceiptThumbnail.tsx
index 7c782a0aa327..5976200975cd 100644
--- a/src/components/EReceiptThumbnail.js
+++ b/src/components/EReceiptThumbnail.tsx
@@ -1,6 +1,7 @@
-import PropTypes from 'prop-types';
import React, {useMemo, useState} from 'react';
+import type {LayoutChangeEvent} from 'react-native';
import {View} from 'react-native';
+import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
@@ -8,24 +9,21 @@ import * as ReportUtils from '@libs/ReportUtils';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
+import type {Transaction} from '@src/types/onyx';
import Icon from './Icon';
import * as eReceiptBGs from './Icon/EReceiptBGs';
import * as Expensicons from './Icon/Expensicons';
import * as MCCIcons from './Icon/MCCIcons';
import Image from './Image';
-import transactionPropTypes from './transactionPropTypes';
-const propTypes = {
- /* TransactionID of the transaction this EReceipt corresponds to */
- // eslint-disable-next-line react/no-unused-prop-types
- transactionID: PropTypes.string.isRequired,
-
- /* Onyx Props */
- transaction: transactionPropTypes,
+type EReceiptThumbnailOnyxProps = {
+ transaction: OnyxEntry;
};
-const defaultProps = {
- transaction: {},
+type EReceiptThumbnailProps = EReceiptThumbnailOnyxProps & {
+ /** TransactionID of the transaction this EReceipt corresponds to. It's used by withOnyx HOC */
+ // eslint-disable-next-line react/no-unused-prop-types
+ transactionID: string;
};
const backgroundImages = {
@@ -37,30 +35,35 @@ const backgroundImages = {
[CONST.ERECEIPT_COLORS.PINK]: eReceiptBGs.EReceiptBG_Pink,
};
-function EReceiptThumbnail({transaction}) {
+function EReceiptThumbnail({transaction}: EReceiptThumbnailProps) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
- // Get receipt colorway, or default to Yellow.
- const {backgroundColor: primaryColor, color: secondaryColor} = StyleUtils.getEReceiptColorStyles(StyleUtils.getEReceiptColorCode(transaction));
const [containerWidth, setContainerWidth] = useState(0);
const [containerHeight, setContainerHeight] = useState(0);
- const onContainerLayout = (event) => {
+ const backgroundImage = useMemo(() => backgroundImages[StyleUtils.getEReceiptColorCode(transaction)], [StyleUtils, transaction]);
+
+ const colorStyles = StyleUtils.getEReceiptColorStyles(StyleUtils.getEReceiptColorCode(transaction));
+ const primaryColor = colorStyles?.backgroundColor;
+ const secondaryColor = colorStyles?.color;
+
+ const onContainerLayout = (event: LayoutChangeEvent) => {
const {width, height} = event.nativeEvent.layout;
setContainerWidth(width);
setContainerHeight(height);
};
- const {mccGroup: transactionMCCGroup} = ReportUtils.getTransactionDetails(transaction);
- const MCCIcon = MCCIcons[`${transactionMCCGroup}`];
+ const transactionDetails = ReportUtils.getTransactionDetails(transaction);
+ const transactionMCCGroup = transactionDetails?.mccGroup;
+ const MCCIcon = transactionMCCGroup ? MCCIcons[`${transactionMCCGroup}`] : undefined;
const isSmall = containerWidth && containerWidth < variables.eReceiptThumbnailSmallBreakpoint;
const isMedium = containerWidth && containerWidth < variables.eReceiptThumbnailMediumBreakpoint;
- let receiptIconWidth = variables.eReceiptIconWidth;
- let receiptIconHeight = variables.eReceiptIconHeight;
- let receiptMCCSize = variables.eReceiptMCCHeightWidth;
+ let receiptIconWidth: number = variables.eReceiptIconWidth;
+ let receiptIconHeight: number = variables.eReceiptIconHeight;
+ let receiptMCCSize: number = variables.eReceiptMCCHeightWidth;
if (isSmall) {
receiptIconWidth = variables.eReceiptIconWidthSmall;
@@ -72,13 +75,11 @@ function EReceiptThumbnail({transaction}) {
receiptMCCSize = variables.eReceiptMCCHeightWidthMedium;
}
- const backgroundImage = useMemo(() => backgroundImages[StyleUtils.getEReceiptColorCode(transaction)], [StyleUtils, transaction]);
-
return (
({
transaction: {
key: ({transactionID}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
},
diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js
index 0791e5113a1d..a723eed446a4 100755
--- a/src/components/EmojiPicker/EmojiPickerMenu/index.js
+++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js
@@ -36,7 +36,7 @@ const throttleTime = Browser.isMobile() ? 200 : 50;
function EmojiPickerMenu({forwardedRef, onEmojiSelected}) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
- const {isSmallScreenWidth} = useWindowDimensions();
+ const {isSmallScreenWidth, windowWidth} = useWindowDimensions();
const {translate} = useLocalize();
const {singleExecution} = useSingleExecution();
const {
@@ -335,7 +335,7 @@ function EmojiPickerMenu({forwardedRef, onEmojiSelected}) {
if (item.header) {
return (
-
+ {translate(`emojiPicker.headers.${code}`)}
);
@@ -368,18 +368,7 @@ function EmojiPickerMenu({forwardedRef, onEmojiSelected}) {
/>
);
},
- [
- preferredSkinTone,
- highlightedIndex,
- isUsingKeyboardMovement,
- highlightFirstEmoji,
- singleExecution,
- styles.emojiHeaderContainer,
- styles.mh4,
- styles.textLabelSupporting,
- translate,
- onEmojiSelected,
- ],
+ [preferredSkinTone, highlightedIndex, isUsingKeyboardMovement, highlightFirstEmoji, singleExecution, translate, onEmojiSelected, isSmallScreenWidth, windowWidth, styles],
);
return (
diff --git a/src/components/EmojiSuggestions.tsx b/src/components/EmojiSuggestions.tsx
index 5904b1521f98..1c0306741048 100644
--- a/src/components/EmojiSuggestions.tsx
+++ b/src/components/EmojiSuggestions.tsx
@@ -1,9 +1,9 @@
import type {ReactElement} from 'react';
import React, {useCallback} from 'react';
import {View} from 'react-native';
+import type {Emoji} from '@assets/emojis/types';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
-import type {SimpleEmoji} from '@libs/EmojiTrie';
import * as EmojiUtils from '@libs/EmojiUtils';
import getStyledTextArray from '@libs/GetStyledTextArray';
import AutoCompleteSuggestions from './AutoCompleteSuggestions';
@@ -16,7 +16,7 @@ type EmojiSuggestionsProps = {
highlightedEmojiIndex?: number;
/** Array of suggested emoji */
- emojis: SimpleEmoji[];
+ emojis: Emoji[];
/** Fired when the user selects an emoji */
onSelect: (index: number) => void;
@@ -40,7 +40,7 @@ type EmojiSuggestionsProps = {
/**
* Create unique keys for each emoji item
*/
-const keyExtractor = (item: SimpleEmoji, index: number): string => `${item.name}+${index}}`;
+const keyExtractor = (item: Emoji, index: number): string => `${item.name}+${index}}`;
function EmojiSuggestions({emojis, onSelect, prefix, isEmojiPickerLarge, preferredSkinToneIndex, highlightedEmojiIndex = 0, measureParentContainer = () => {}}: EmojiSuggestionsProps) {
const styles = useThemeStyles();
@@ -49,7 +49,7 @@ function EmojiSuggestions({emojis, onSelect, prefix, isEmojiPickerLarge, preferr
* Render an emoji suggestion menu item component.
*/
const renderSuggestionMenuItem = useCallback(
- (item: SimpleEmoji): ReactElement => {
+ (item: Emoji): ReactElement => {
const styledTextArray = getStyledTextArray(item.name, prefix);
return (
diff --git a/src/components/EnvironmentBadge.tsx b/src/components/EnvironmentBadge.tsx
index 3a8445f62880..ceb4acf1b9ee 100644
--- a/src/components/EnvironmentBadge.tsx
+++ b/src/components/EnvironmentBadge.tsx
@@ -30,7 +30,7 @@ function EnvironmentBadge() {
error={environment !== CONST.ENVIRONMENT.STAGING && environment !== CONST.ENVIRONMENT.ADHOC}
text={text}
badgeStyles={[styles.alignSelfStart, styles.headerEnvBadge]}
- textStyles={[styles.headerEnvBadgeText]}
+ textStyles={[styles.headerEnvBadgeText, {fontWeight: '700'}]}
environment={environment}
/>
);
diff --git a/src/components/FlatList/MVCPFlatList.js b/src/components/FlatList/MVCPFlatList.js
new file mode 100644
index 000000000000..0abb1dc4a873
--- /dev/null
+++ b/src/components/FlatList/MVCPFlatList.js
@@ -0,0 +1,207 @@
+/* eslint-disable es/no-optional-chaining, es/no-nullish-coalescing-operators, react/prop-types */
+import PropTypes from 'prop-types';
+import React from 'react';
+import {FlatList} from 'react-native';
+
+function mergeRefs(...args) {
+ return function forwardRef(node) {
+ args.forEach((ref) => {
+ if (ref == null) {
+ return;
+ }
+ if (typeof ref === 'function') {
+ ref(node);
+ return;
+ }
+ if (typeof ref === 'object') {
+ // eslint-disable-next-line no-param-reassign
+ ref.current = node;
+ return;
+ }
+ console.error(`mergeRefs cannot handle Refs of type boolean, number or string, received ref ${String(ref)}`);
+ });
+ };
+}
+
+function useMergeRefs(...args) {
+ return React.useMemo(
+ () => mergeRefs(...args),
+ // eslint-disable-next-line
+ [...args],
+ );
+}
+
+const MVCPFlatList = React.forwardRef(({maintainVisibleContentPosition, horizontal, onScroll, ...props}, forwardedRef) => {
+ const {minIndexForVisible: mvcpMinIndexForVisible, autoscrollToTopThreshold: mvcpAutoscrollToTopThreshold} = maintainVisibleContentPosition ?? {};
+ const scrollRef = React.useRef(null);
+ const prevFirstVisibleOffsetRef = React.useRef(null);
+ const firstVisibleViewRef = React.useRef(null);
+ const mutationObserverRef = React.useRef(null);
+ const lastScrollOffsetRef = React.useRef(0);
+
+ const getScrollOffset = React.useCallback(() => {
+ if (scrollRef.current == null) {
+ return 0;
+ }
+ return horizontal ? scrollRef.current.getScrollableNode().scrollLeft : scrollRef.current.getScrollableNode().scrollTop;
+ }, [horizontal]);
+
+ const getContentView = React.useCallback(() => scrollRef.current?.getScrollableNode().childNodes[0], []);
+
+ const scrollToOffset = React.useCallback(
+ (offset, animated) => {
+ const behavior = animated ? 'smooth' : 'instant';
+ scrollRef.current?.getScrollableNode().scroll(horizontal ? {left: offset, behavior} : {top: offset, behavior});
+ },
+ [horizontal],
+ );
+
+ const prepareForMaintainVisibleContentPosition = React.useCallback(() => {
+ if (mvcpMinIndexForVisible == null) {
+ return;
+ }
+
+ const contentView = getContentView();
+ if (contentView == null) {
+ return;
+ }
+
+ const scrollOffset = getScrollOffset();
+
+ const contentViewLength = contentView.childNodes.length;
+ for (let i = mvcpMinIndexForVisible; i < contentViewLength; i++) {
+ const subview = contentView.childNodes[i];
+ const subviewOffset = horizontal ? subview.offsetLeft : subview.offsetTop;
+ if (subviewOffset > scrollOffset || i === contentViewLength - 1) {
+ prevFirstVisibleOffsetRef.current = subviewOffset;
+ firstVisibleViewRef.current = subview;
+ break;
+ }
+ }
+ }, [getContentView, getScrollOffset, mvcpMinIndexForVisible, horizontal]);
+
+ const adjustForMaintainVisibleContentPosition = React.useCallback(() => {
+ if (mvcpMinIndexForVisible == null) {
+ return;
+ }
+
+ const firstVisibleView = firstVisibleViewRef.current;
+ const prevFirstVisibleOffset = prevFirstVisibleOffsetRef.current;
+ if (firstVisibleView == null || prevFirstVisibleOffset == null) {
+ return;
+ }
+
+ const firstVisibleViewOffset = horizontal ? firstVisibleView.offsetLeft : firstVisibleView.offsetTop;
+ const delta = firstVisibleViewOffset - prevFirstVisibleOffset;
+ if (Math.abs(delta) > 0.5) {
+ const scrollOffset = getScrollOffset();
+ prevFirstVisibleOffsetRef.current = firstVisibleViewOffset;
+ scrollToOffset(scrollOffset + delta, false);
+ if (mvcpAutoscrollToTopThreshold != null && scrollOffset <= mvcpAutoscrollToTopThreshold) {
+ scrollToOffset(0, true);
+ }
+ }
+ }, [getScrollOffset, scrollToOffset, mvcpMinIndexForVisible, mvcpAutoscrollToTopThreshold, horizontal]);
+
+ const setupMutationObserver = React.useCallback(() => {
+ const contentView = getContentView();
+ if (contentView == null) {
+ return;
+ }
+
+ mutationObserverRef.current?.disconnect();
+
+ const mutationObserver = new MutationObserver(() => {
+ // This needs to execute after scroll events are dispatched, but
+ // in the same tick to avoid flickering. rAF provides the right timing.
+ requestAnimationFrame(() => {
+ // Chrome adjusts scroll position when elements are added at the top of the
+ // view. We want to have the same behavior as react-native / Safari so we
+ // reset the scroll position to the last value we got from an event.
+ const lastScrollOffset = lastScrollOffsetRef.current;
+ const scrollOffset = getScrollOffset();
+ if (lastScrollOffset !== scrollOffset) {
+ scrollToOffset(lastScrollOffset, false);
+ }
+
+ adjustForMaintainVisibleContentPosition();
+ });
+ });
+ mutationObserver.observe(contentView, {
+ attributes: true,
+ childList: true,
+ subtree: true,
+ });
+
+ mutationObserverRef.current = mutationObserver;
+ }, [adjustForMaintainVisibleContentPosition, getContentView, getScrollOffset, scrollToOffset]);
+
+ React.useEffect(() => {
+ requestAnimationFrame(() => {
+ prepareForMaintainVisibleContentPosition();
+ setupMutationObserver();
+ });
+ }, [prepareForMaintainVisibleContentPosition, setupMutationObserver]);
+
+ const setMergedRef = useMergeRefs(scrollRef, forwardedRef);
+
+ const onRef = React.useCallback(
+ (newRef) => {
+ // Make sure to only call refs and re-attach listeners if the node changed.
+ if (newRef == null || newRef === scrollRef.current) {
+ return;
+ }
+
+ setMergedRef(newRef);
+ prepareForMaintainVisibleContentPosition();
+ setupMutationObserver();
+ },
+ [prepareForMaintainVisibleContentPosition, setMergedRef, setupMutationObserver],
+ );
+
+ React.useEffect(() => {
+ const mutationObserver = mutationObserverRef.current;
+ return () => {
+ mutationObserver?.disconnect();
+ };
+ }, []);
+
+ const onScrollInternal = React.useCallback(
+ (ev) => {
+ lastScrollOffsetRef.current = getScrollOffset();
+
+ prepareForMaintainVisibleContentPosition();
+
+ onScroll?.(ev);
+ },
+ [getScrollOffset, prepareForMaintainVisibleContentPosition, onScroll],
+ );
+
+ return (
+
+ );
+});
+
+MVCPFlatList.displayName = 'MVCPFlatList';
+MVCPFlatList.propTypes = {
+ maintainVisibleContentPosition: PropTypes.shape({
+ minIndexForVisible: PropTypes.number.isRequired,
+ autoscrollToTopThreshold: PropTypes.number,
+ }),
+ horizontal: PropTypes.bool,
+};
+
+MVCPFlatList.defaultProps = {
+ maintainVisibleContentPosition: null,
+ horizontal: false,
+};
+
+export default MVCPFlatList;
diff --git a/src/components/FlatList/index.web.js b/src/components/FlatList/index.web.js
new file mode 100644
index 000000000000..7299776db9bc
--- /dev/null
+++ b/src/components/FlatList/index.web.js
@@ -0,0 +1,3 @@
+import MVCPFlatList from './MVCPFlatList';
+
+export default MVCPFlatList;
diff --git a/src/components/FloatingActionButton.js b/src/components/FloatingActionButton.tsx
similarity index 81%
rename from src/components/FloatingActionButton.js
rename to src/components/FloatingActionButton.tsx
index 59e741001063..5f75bf535319 100644
--- a/src/components/FloatingActionButton.js
+++ b/src/components/FloatingActionButton.tsx
@@ -1,5 +1,6 @@
-import PropTypes from 'prop-types';
-import React, {useEffect, useRef} from 'react';
+import type {ForwardedRef} from 'react';
+import React, {forwardRef, useEffect, useRef} from 'react';
+import type {GestureResponderEvent, Role} from 'react-native';
import {Platform, View} from 'react-native';
import Animated, {createAnimatedPropAdapter, Easing, interpolateColor, processColor, useAnimatedProps, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
import Svg, {Path} from 'react-native-svg';
@@ -16,8 +17,18 @@ AnimatedPath.displayName = 'AnimatedPath';
const AnimatedPressable = Animated.createAnimatedComponent(PressableWithFeedback);
AnimatedPressable.displayName = 'AnimatedPressable';
+type AdapterPropsRecord = {
+ type: number;
+ payload?: number | null;
+};
+
+type AdapterProps = {
+ fill?: string | AdapterPropsRecord;
+ stroke?: string | AdapterPropsRecord;
+};
+
const adapter = createAnimatedPropAdapter(
- (props) => {
+ (props: AdapterProps) => {
// eslint-disable-next-line rulesdir/prefer-underscore-method
if (Object.keys(props).includes('fill')) {
// eslint-disable-next-line no-param-reassign
@@ -31,31 +42,27 @@ const adapter = createAnimatedPropAdapter(
},
['fill', 'stroke'],
);
-adapter.propTypes = {
- fill: PropTypes.string,
- stroke: PropTypes.string,
-};
-const propTypes = {
+type FloatingActionButtonProps = {
/* Callback to fire on request to toggle the FloatingActionButton */
- onPress: PropTypes.func.isRequired,
+ onPress: (event: GestureResponderEvent | KeyboardEvent | undefined) => void;
/* Current state (active or not active) of the component */
- isActive: PropTypes.bool.isRequired,
+ isActive: boolean;
/* An accessibility label for the button */
- accessibilityLabel: PropTypes.string.isRequired,
+ accessibilityLabel: string;
/* An accessibility role for the button */
- role: PropTypes.string.isRequired,
+ role: Role;
};
-const FloatingActionButton = React.forwardRef(({onPress, isActive, accessibilityLabel, role}, ref) => {
+function FloatingActionButton({onPress, isActive, accessibilityLabel, role}: FloatingActionButtonProps, ref: ForwardedRef) {
const {success, buttonDefaultBG, textLight, textDark} = useTheme();
const styles = useThemeStyles();
const borderRadius = styles.floatingActionButton.borderRadius;
const {translate} = useLocalize();
- const fabPressable = useRef(null);
+ const fabPressable = useRef(null);
const sharedValue = useSharedValue(isActive ? 1 : 0);
const buttonRef = ref;
@@ -94,7 +101,8 @@ const FloatingActionButton = React.forwardRef(({onPress, isActive, accessibility
{
fabPressable.current = el;
- if (buttonRef) {
+
+ if (buttonRef && 'current' in buttonRef) {
buttonRef.current = el;
}
}}
@@ -103,7 +111,7 @@ const FloatingActionButton = React.forwardRef(({onPress, isActive, accessibility
pressDimmingValue={1}
onPress={(e) => {
// Drop focus to avoid blue focus ring.
- fabPressable.current.blur();
+ fabPressable.current?.blur();
onPress(e);
}}
onLongPress={() => {}}
@@ -122,9 +130,8 @@ const FloatingActionButton = React.forwardRef(({onPress, isActive, accessibility
);
-});
+}
-FloatingActionButton.propTypes = propTypes;
FloatingActionButton.displayName = 'FloatingActionButton';
-export default FloatingActionButton;
+export default forwardRef(FloatingActionButton);
diff --git a/src/components/Form.js b/src/components/Form.js
deleted file mode 100644
index 7b6f587e7bd1..000000000000
--- a/src/components/Form.js
+++ /dev/null
@@ -1,592 +0,0 @@
-import lodashGet from 'lodash/get';
-import PropTypes from 'prop-types';
-import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react';
-import {Keyboard, ScrollView, StyleSheet} from 'react-native';
-import {withOnyx} from 'react-native-onyx';
-import _ from 'underscore';
-import useThemeStyles from '@hooks/useThemeStyles';
-import compose from '@libs/compose';
-import * as ErrorUtils from '@libs/ErrorUtils';
-import FormUtils from '@libs/FormUtils';
-import * as ValidationUtils from '@libs/ValidationUtils';
-import Visibility from '@libs/Visibility';
-import stylePropTypes from '@styles/stylePropTypes';
-import * as FormActions from '@userActions/FormActions';
-import CONST from '@src/CONST';
-import FormAlertWithSubmitButton from './FormAlertWithSubmitButton';
-import FormSubmit from './FormSubmit';
-import networkPropTypes from './networkPropTypes';
-import {withNetwork} from './OnyxProvider';
-import SafeAreaConsumer from './SafeAreaConsumer';
-import ScrollViewWithContext from './ScrollViewWithContext';
-import withLocalize, {withLocalizePropTypes} from './withLocalize';
-
-const propTypes = {
- /** A unique Onyx key identifying the form */
- formID: PropTypes.string.isRequired,
-
- /** Text to be displayed in the submit button */
- submitButtonText: PropTypes.string,
-
- /** Controls the submit button's visibility */
- isSubmitButtonVisible: PropTypes.bool,
-
- /** Callback to validate the form */
- validate: PropTypes.func,
-
- /** Callback to submit the form */
- onSubmit: PropTypes.func.isRequired,
-
- /** Children to render. */
- children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]).isRequired,
-
- /* Onyx Props */
-
- /** Contains the form state that must be accessed outside of the component */
- formState: PropTypes.shape({
- /** Controls the loading state of the form */
- isLoading: PropTypes.bool,
-
- /** Server side errors keyed by microtime */
- errors: PropTypes.objectOf(PropTypes.string),
-
- /** Field-specific server side errors keyed by microtime */
- errorFields: PropTypes.objectOf(PropTypes.objectOf(PropTypes.string)),
- }),
-
- /** Contains draft values for each input in the form */
- // eslint-disable-next-line react/forbid-prop-types
- draftValues: PropTypes.object,
-
- /** Should the button be enabled when offline */
- enabledWhenOffline: PropTypes.bool,
-
- /** Whether the form submit action is dangerous */
- isSubmitActionDangerous: PropTypes.bool,
-
- /** Whether the validate() method should run on input changes */
- shouldValidateOnChange: PropTypes.bool,
-
- /** Whether the validate() method should run on blur */
- shouldValidateOnBlur: PropTypes.bool,
-
- /** Whether ScrollWithContext should be used instead of regular ScrollView.
- * Set to true when there's a nested Picker component in Form.
- */
- scrollContextEnabled: PropTypes.bool,
-
- /** Container styles */
- style: stylePropTypes,
-
- /** Submit button container styles */
- // eslint-disable-next-line react/forbid-prop-types
- submitButtonStyles: PropTypes.arrayOf(PropTypes.object),
-
- /** Custom content to display in the footer after submit button */
- footerContent: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
-
- /** Information about the network */
- network: networkPropTypes.isRequired,
-
- /** Style for the error message for submit button */
- errorMessageStyle: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
-
- ...withLocalizePropTypes,
-};
-
-const defaultProps = {
- isSubmitButtonVisible: true,
- formState: {
- isLoading: false,
- },
- draftValues: {},
- enabledWhenOffline: false,
- isSubmitActionDangerous: false,
- scrollContextEnabled: false,
- shouldValidateOnChange: true,
- shouldValidateOnBlur: true,
- footerContent: null,
- style: [],
- errorMessageStyle: [],
- submitButtonStyles: [],
- validate: () => ({}),
- submitButtonText: '',
-};
-
-const Form = forwardRef((props, forwardedRef) => {
- const styles = useThemeStyles();
- const [errors, setErrors] = useState({});
- const [inputValues, setInputValues] = useState(() => ({...props.draftValues}));
- const formRef = useRef(null);
- const formContentRef = useRef(null);
- const inputRefs = useRef({});
- const touchedInputs = useRef({});
- const focusedInput = useRef(null);
- const isFirstRender = useRef(true);
-
- const {validate, onSubmit, children} = props;
-
- const hasServerError = useMemo(() => Boolean(props.formState) && !_.isEmpty(props.formState.errors), [props.formState]);
-
- /**
- * @param {Object} values - An object containing the value of each inputID, e.g. {inputID1: value1, inputID2: value2}
- * @returns {Object} - An object containing the errors for each inputID, e.g. {inputID1: error1, inputID2: error2}
- */
- const onValidate = useCallback(
- (values, shouldClearServerError = true) => {
- // Trim all string values
- const trimmedStringValues = ValidationUtils.prepareValues(values);
-
- if (shouldClearServerError) {
- FormActions.setErrors(props.formID, null);
- }
- FormActions.setErrorFields(props.formID, null);
-
- // Run any validations passed as a prop
- const validationErrors = validate(trimmedStringValues);
-
- // Validate the input for html tags. It should supercede any other error
- _.each(trimmedStringValues, (inputValue, inputID) => {
- // If the input value is empty OR is non-string, we don't need to validate it for HTML tags
- if (!inputValue || !_.isString(inputValue)) {
- return;
- }
- const foundHtmlTagIndex = inputValue.search(CONST.VALIDATE_FOR_HTML_TAG_REGEX);
- const leadingSpaceIndex = inputValue.search(CONST.VALIDATE_FOR_LEADINGSPACES_HTML_TAG_REGEX);
-
- // Return early if there are no HTML characters
- if (leadingSpaceIndex === -1 && foundHtmlTagIndex === -1) {
- return;
- }
-
- const matchedHtmlTags = inputValue.match(CONST.VALIDATE_FOR_HTML_TAG_REGEX);
- let isMatch = _.some(CONST.WHITELISTED_TAGS, (r) => r.test(inputValue));
- // Check for any matches that the original regex (foundHtmlTagIndex) matched
- if (matchedHtmlTags) {
- // Check if any matched inputs does not match in WHITELISTED_TAGS list and return early if needed.
- for (let i = 0; i < matchedHtmlTags.length; i++) {
- const htmlTag = matchedHtmlTags[i];
- isMatch = _.some(CONST.WHITELISTED_TAGS, (r) => r.test(htmlTag));
- if (!isMatch) {
- break;
- }
- }
- }
-
- if (isMatch && leadingSpaceIndex === -1) {
- return;
- }
-
- // Add a validation error here because it is a string value that contains HTML characters
- validationErrors[inputID] = 'common.error.invalidCharacter';
- });
-
- if (!_.isObject(validationErrors)) {
- throw new Error('Validate callback must return an empty object or an object with shape {inputID: error}');
- }
-
- const touchedInputErrors = _.pick(validationErrors, (inputValue, inputID) => Boolean(touchedInputs.current[inputID]));
-
- if (!_.isEqual(errors, touchedInputErrors)) {
- setErrors(touchedInputErrors);
- }
-
- return touchedInputErrors;
- },
- [props.formID, validate, errors],
- );
-
- useEffect(() => {
- // We want to skip Form validation on initial render.
- // This also avoids a bug where we immediately clear server errors when the loading indicator unmounts and Form remounts with server errors.
- if (isFirstRender.current) {
- isFirstRender.current = false;
- return;
- }
-
- onValidate(inputValues);
-
- // eslint-disable-next-line react-hooks/exhaustive-deps -- we just want to revalidate the form on update if the preferred locale changed on another device so that errors get translated
- }, [props.preferredLocale]);
-
- const errorMessage = useMemo(() => {
- const latestErrorMessage = ErrorUtils.getLatestErrorMessage(props.formState);
- return typeof latestErrorMessage === 'string' ? latestErrorMessage : '';
- }, [props.formState]);
-
- /**
- * @param {String} inputID - The inputID of the input being touched
- */
- const setTouchedInput = useCallback(
- (inputID) => {
- touchedInputs.current[inputID] = true;
- },
- [touchedInputs],
- );
-
- const submit = useCallback(() => {
- // Return early if the form is already submitting to avoid duplicate submission
- if (props.formState.isLoading) {
- return;
- }
-
- // Trim all string values
- const trimmedStringValues = ValidationUtils.prepareValues(inputValues);
-
- // Touches all form inputs so we can validate the entire form
- _.each(inputRefs.current, (inputRef, inputID) => (touchedInputs.current[inputID] = true));
-
- // Validate form and return early if any errors are found
- if (!_.isEmpty(onValidate(trimmedStringValues))) {
- return;
- }
-
- // Do not submit form if network is offline and the form is not enabled when offline
- if (props.network.isOffline && !props.enabledWhenOffline) {
- return;
- }
-
- // Call submit handler
- onSubmit(trimmedStringValues);
- }, [props.formState.isLoading, props.network.isOffline, props.enabledWhenOffline, inputValues, onValidate, onSubmit]);
-
- /**
- * Resets the form
- */
- const resetForm = useCallback(
- (optionalValue) => {
- _.each(inputValues, (inputRef, inputID) => {
- setInputValues((prevState) => {
- const copyPrevState = _.clone(prevState);
-
- touchedInputs.current[inputID] = false;
- copyPrevState[inputID] = optionalValue[inputID] || '';
-
- return copyPrevState;
- });
- });
- setErrors({});
- },
- [inputValues],
- );
-
- useImperativeHandle(forwardedRef, () => ({
- resetForm,
- }));
-
- /**
- * Loops over Form's children and automatically supplies Form props to them
- *
- * @param {Array | Function | Node} children - An array containing all Form children
- * @returns {React.Component}
- */
- const childrenWrapperWithProps = useCallback(
- (childNodes) => {
- const childrenElements = React.Children.map(childNodes, (child) => {
- // Just render the child if it is not a valid React element, e.g. text within a component
- if (!React.isValidElement(child)) {
- return child;
- }
-
- // Depth first traversal of the render tree as the input element is likely to be the last node
- if (child.props.children) {
- return React.cloneElement(child, {
- children: childrenWrapperWithProps(child.props.children),
- });
- }
-
- // Look for any inputs nested in a custom component, e.g AddressForm or IdentityForm
- if (_.isFunction(child.type)) {
- const childNode = new child.type(child.props);
-
- // If the custom component has a render method, use it to get the nested children
- const nestedChildren = _.isFunction(childNode.render) ? childNode.render() : childNode;
-
- // Render the custom component if it's a valid React element
- // If the custom component has nested children, Loop over them and supply From props
- if (React.isValidElement(nestedChildren) || lodashGet(nestedChildren, 'props.children')) {
- return childrenWrapperWithProps(nestedChildren);
- }
-
- // Just render the child if it's custom component not a valid React element, or if it hasn't children
- return child;
- }
-
- // We check if the child has the inputID prop.
- // We don't want to pass form props to non form components, e.g. View, Text, etc
- if (!child.props.inputID) {
- return child;
- }
-
- // We clone the child passing down all form props
- const inputID = child.props.inputID;
- let defaultValue;
-
- // We need to make sure that checkboxes have correct
- // value assigned from the list of draft values
- // https://github.com/Expensify/App/issues/16885#issuecomment-1520846065
- if (_.isBoolean(props.draftValues[inputID])) {
- defaultValue = props.draftValues[inputID];
- } else {
- defaultValue = props.draftValues[inputID] || child.props.defaultValue;
- }
-
- // We want to initialize the input value if it's undefined
- if (_.isUndefined(inputValues[inputID])) {
- // eslint-disable-next-line es/no-nullish-coalescing-operators
- inputValues[inputID] = defaultValue ?? '';
- }
-
- // We force the form to set the input value from the defaultValue props if there is a saved valid value
- if (child.props.shouldUseDefaultValue) {
- inputValues[inputID] = child.props.defaultValue;
- }
-
- if (!_.isUndefined(child.props.value)) {
- inputValues[inputID] = child.props.value;
- }
-
- const errorFields = lodashGet(props.formState, 'errorFields', {});
- const fieldErrorMessage =
- _.chain(errorFields[inputID])
- .keys()
- .sortBy()
- .reverse()
- .map((key) => errorFields[inputID][key])
- .first()
- .value() || '';
-
- return React.cloneElement(child, {
- ref: (node) => {
- inputRefs.current[inputID] = node;
-
- const {ref} = child;
- if (_.isFunction(ref)) {
- ref(node);
- }
- },
- value: inputValues[inputID],
- // As the text input is controlled, we never set the defaultValue prop
- // as this is already happening by the value prop.
- defaultValue: undefined,
- errorText: errors[inputID] || fieldErrorMessage,
- onFocus: (event) => {
- focusedInput.current = inputID;
- if (_.isFunction(child.props.onFocus)) {
- child.props.onFocus(event);
- }
- },
- onBlur: (event) => {
- // Only run validation when user proactively blurs the input.
- if (Visibility.isVisible() && Visibility.hasFocus()) {
- const relatedTargetId = lodashGet(event, 'nativeEvent.relatedTarget.id');
- // We delay the validation in order to prevent Checkbox loss of focus when
- // the user are focusing a TextInput and proceeds to toggle a CheckBox in
- // web and mobile web platforms.
-
- setTimeout(() => {
- if (
- relatedTargetId &&
- _.includes([CONST.OVERLAY.BOTTOM_BUTTON_NATIVE_ID, CONST.OVERLAY.TOP_BUTTON_NATIVE_ID, CONST.BACK_BUTTON_NATIVE_ID], relatedTargetId)
- ) {
- return;
- }
- setTouchedInput(inputID);
- if (props.shouldValidateOnBlur) {
- onValidate(inputValues, !hasServerError);
- }
- }, 200);
- }
-
- if (_.isFunction(child.props.onBlur)) {
- child.props.onBlur(event);
- }
- },
- onTouched: () => {
- setTouchedInput(inputID);
- },
- onInputChange: (value, key) => {
- const inputKey = key || inputID;
-
- if (focusedInput.current && focusedInput.current !== inputKey) {
- setTouchedInput(focusedInput.current);
- }
-
- setInputValues((prevState) => {
- const newState = {
- ...prevState,
- [inputKey]: value,
- };
-
- if (props.shouldValidateOnChange) {
- onValidate(newState);
- }
- return newState;
- });
-
- if (child.props.shouldSaveDraft) {
- FormActions.setDraftValues(props.formID, {[inputKey]: value});
- }
-
- if (child.props.onValueChange) {
- child.props.onValueChange(value, inputKey);
- }
- },
- });
- });
-
- return childrenElements;
- },
- [
- errors,
- inputRefs,
- inputValues,
- onValidate,
- props.draftValues,
- props.formID,
- props.formState,
- setTouchedInput,
- props.shouldValidateOnBlur,
- props.shouldValidateOnChange,
- hasServerError,
- ],
- );
-
- const scrollViewContent = useCallback(
- (safeAreaPaddingBottomStyle) => (
-
- {childrenWrapperWithProps(_.isFunction(children) ? children({inputValues}) : children)}
- {props.isSubmitButtonVisible && (
- 0 || Boolean(errorMessage) || !_.isEmpty(props.formState.errorFields)}
- isLoading={props.formState.isLoading}
- message={_.isEmpty(props.formState.errorFields) ? errorMessage : null}
- onSubmit={submit}
- footerContent={props.footerContent}
- onFixTheErrorsLinkPressed={() => {
- const errorFields = !_.isEmpty(errors) ? errors : props.formState.errorFields;
- const focusKey = _.find(_.keys(inputRefs.current), (key) => _.keys(errorFields).includes(key));
- const focusInput = inputRefs.current[focusKey];
-
- // Dismiss the keyboard for non-text fields by checking if the component has the isFocused method, as only TextInput has this method.
- if (typeof focusInput.isFocused !== 'function') {
- Keyboard.dismiss();
- }
-
- // We subtract 10 to scroll slightly above the input
- if (focusInput.measureLayout && typeof focusInput.measureLayout === 'function') {
- // We measure relative to the content root, not the scroll view, as that gives
- // consistent results across mobile and web
- focusInput.measureLayout(formContentRef.current, (x, y) => formRef.current.scrollTo({y: y - 10, animated: false}));
- }
-
- // Focus the input after scrolling, as on the Web it gives a slightly better visual result
- if (focusInput.focus && typeof focusInput.focus === 'function') {
- focusInput.focus();
- }
- }}
- containerStyles={[styles.mh0, styles.mt5, styles.flex1, ...props.submitButtonStyles]}
- enabledWhenOffline={props.enabledWhenOffline}
- isSubmitActionDangerous={props.isSubmitActionDangerous}
- useSmallerSubmitButtonSize={props.useSmallerSubmitButtonSize}
- disablePressOnEnter
- errorMessageStyle={props.errorMessageStyle}
- />
- )}
-
- ),
-
- [
- props.style,
- props.isSubmitButtonVisible,
- props.submitButtonText,
- props.useSmallerSubmitButtonSize,
- props.errorMessageStyle,
- props.formState.errorFields,
- props.formState.isLoading,
- props.footerContent,
- props.submitButtonStyles,
- props.enabledWhenOffline,
- props.isSubmitActionDangerous,
- submit,
- childrenWrapperWithProps,
- children,
- inputValues,
- errors,
- errorMessage,
- styles.mh0,
- styles.mt5,
- styles.flex1,
- ],
- );
-
- useEffect(() => {
- _.each(inputRefs.current, (inputRef, inputID) => {
- if (inputRef) {
- return;
- }
-
- delete inputRefs.current[inputID];
- delete touchedInputs.current[inputID];
-
- setInputValues((prevState) => {
- const copyPrevState = _.clone(prevState);
-
- delete copyPrevState[inputID];
-
- return copyPrevState;
- });
- });
- // We need to verify that all references and values are still actual.
- // We should not store it when e.g. some input has been unmounted.
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [children]);
-
- return (
-
- {({safeAreaPaddingBottomStyle}) =>
- props.scrollContextEnabled ? (
-
- {scrollViewContent(safeAreaPaddingBottomStyle)}
-
- ) : (
-
- {scrollViewContent(safeAreaPaddingBottomStyle)}
-
- )
- }
-
- );
-});
-
-Form.displayName = 'Form';
-Form.propTypes = propTypes;
-Form.defaultProps = defaultProps;
-
-export default compose(
- withLocalize,
- withNetwork(),
- withOnyx({
- formState: {
- key: (props) => props.formID,
- },
- draftValues: {
- key: (props) => FormUtils.getDraftKey(props.formID),
- },
- }),
-)(Form);
diff --git a/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js b/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.tsx
similarity index 52%
rename from src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js
rename to src/components/HTMLEngineProvider/BaseHTMLEngineProvider.tsx
index 0b5cbad29983..690f2fc6883a 100755
--- a/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js
+++ b/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.tsx
@@ -1,27 +1,19 @@
-import PropTypes from 'prop-types';
import React, {useMemo} from 'react';
-import {defaultHTMLElementModels, RenderHTMLConfigProvider, TRenderEngineProvider} from 'react-native-render-html';
-import _ from 'underscore';
+import type {TextProps} from 'react-native';
+import {HTMLContentModel, HTMLElementModel, RenderHTMLConfigProvider, TRenderEngineProvider} from 'react-native-render-html';
import useThemeStyles from '@hooks/useThemeStyles';
import convertToLTR from '@libs/convertToLTR';
-import singleFontFamily from '@styles/utils/fontFamily/singleFontFamily';
+import FontUtils from '@styles/utils/FontUtils';
+import type ChildrenProps from '@src/types/utils/ChildrenProps';
import * as HTMLEngineUtils from './htmlEngineUtils';
import htmlRenderers from './HTMLRenderers';
-const propTypes = {
+type BaseHTMLEngineProviderProps = ChildrenProps & {
/** Whether text elements should be selectable */
- textSelectable: PropTypes.bool,
+ textSelectable?: boolean;
/** Handle line breaks according to the HTML standard (default on web) */
- enableExperimentalBRCollapsing: PropTypes.bool,
-
- children: PropTypes.node,
-};
-
-const defaultProps = {
- textSelectable: false,
- children: null,
- enableExperimentalBRCollapsing: false,
+ enableExperimentalBRCollapsing?: boolean;
};
// We are using the explicit composite architecture for performance gains.
@@ -29,52 +21,62 @@ const defaultProps = {
// context to RenderHTMLSource components. See https://git.io/JRcZb
// Beware that each prop should be referentialy stable between renders to avoid
// costly invalidations and commits.
-function BaseHTMLEngineProvider(props) {
+function BaseHTMLEngineProvider({textSelectable = false, children, enableExperimentalBRCollapsing = false}: BaseHTMLEngineProviderProps) {
const styles = useThemeStyles();
// Declare nonstandard tags and their content model here
+ /* eslint-disable @typescript-eslint/naming-convention */
const customHTMLElementModels = useMemo(
() => ({
- edited: defaultHTMLElementModels.span.extend({
+ edited: HTMLElementModel.fromCustomModel({
tagName: 'edited',
+ contentModel: HTMLContentModel.textual,
}),
- 'alert-text': defaultHTMLElementModels.div.extend({
+ 'alert-text': HTMLElementModel.fromCustomModel({
tagName: 'alert-text',
mixedUAStyles: {...styles.formError, ...styles.mb0},
+ contentModel: HTMLContentModel.block,
}),
- 'muted-text': defaultHTMLElementModels.div.extend({
+ 'muted-text': HTMLElementModel.fromCustomModel({
tagName: 'muted-text',
mixedUAStyles: {...styles.colorMuted, ...styles.mb0},
+ contentModel: HTMLContentModel.block,
}),
- comment: defaultHTMLElementModels.div.extend({
+ comment: HTMLElementModel.fromCustomModel({
tagName: 'comment',
mixedUAStyles: {whiteSpace: 'pre'},
+ contentModel: HTMLContentModel.block,
}),
- 'email-comment': defaultHTMLElementModels.div.extend({
+ 'email-comment': HTMLElementModel.fromCustomModel({
tagName: 'email-comment',
mixedUAStyles: {whiteSpace: 'normal'},
+ contentModel: HTMLContentModel.block,
}),
- strong: defaultHTMLElementModels.span.extend({
+ strong: HTMLElementModel.fromCustomModel({
tagName: 'strong',
mixedUAStyles: {whiteSpace: 'pre'},
+ contentModel: HTMLContentModel.textual,
}),
- 'mention-user': defaultHTMLElementModels.span.extend({tagName: 'mention-user'}),
- 'mention-here': defaultHTMLElementModels.span.extend({tagName: 'mention-here'}),
- 'next-step': defaultHTMLElementModels.span.extend({
+ 'mention-user': HTMLElementModel.fromCustomModel({tagName: 'mention-user', contentModel: HTMLContentModel.textual}),
+ 'mention-here': HTMLElementModel.fromCustomModel({tagName: 'mention-here', contentModel: HTMLContentModel.textual}),
+ 'next-step': HTMLElementModel.fromCustomModel({
tagName: 'next-step',
- mixedUAStyles: {...styles.textLabelSupporting},
+ mixedUAStyles: {...styles.textLabelSupporting, ...styles.lh16},
+ contentModel: HTMLContentModel.textual,
}),
- 'next-step-email': defaultHTMLElementModels.span.extend({tagName: 'next-step-email'}),
- video: defaultHTMLElementModels.div.extend({
+ 'next-step-email': HTMLElementModel.fromCustomModel({tagName: 'next-step-email', contentModel: HTMLContentModel.textual}),
+ video: HTMLElementModel.fromCustomModel({
tagName: 'video',
mixedUAStyles: {whiteSpace: 'pre'},
+ contentModel: HTMLContentModel.block,
}),
}),
- [styles.colorMuted, styles.formError, styles.mb0, styles.textLabelSupporting],
+ [styles.colorMuted, styles.formError, styles.mb0, styles.textLabelSupporting, styles.lh16],
);
+ /* eslint-enable @typescript-eslint/naming-convention */
// We need to memoize this prop to make it referentially stable.
- const defaultTextProps = useMemo(() => ({selectable: props.textSelectable, allowFontScaling: false, textBreakStrategy: 'simple'}), [props.textSelectable]);
+ const defaultTextProps: TextProps = useMemo(() => ({selectable: textSelectable, allowFontScaling: false, textBreakStrategy: 'simple'}), [textSelectable]);
const defaultViewProps = {style: [styles.alignItemsStart, styles.userSelectText]};
return (
(text.data = convertToLTR(text.data)),
@@ -91,18 +93,17 @@ function BaseHTMLEngineProvider(props) {
- {props.children}
+ {children}
);
}
BaseHTMLEngineProvider.displayName = 'BaseHTMLEngineProvider';
-BaseHTMLEngineProvider.propTypes = propTypes;
-BaseHTMLEngineProvider.defaultProps = defaultProps;
export default BaseHTMLEngineProvider;
diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/BasePreRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer.js
similarity index 76%
rename from src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/BasePreRenderer.js
rename to src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer.js
index 07954cc97a00..27eff02d63ea 100644
--- a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/BasePreRenderer.js
+++ b/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer.js
@@ -1,14 +1,14 @@
import PropTypes from 'prop-types';
-import React, {forwardRef} from 'react';
-import {ScrollView, View} from 'react-native';
+import React from 'react';
+import {View} from 'react-native';
import _ from 'underscore';
-import htmlRendererPropTypes from '@components/HTMLEngineProvider/HTMLRenderers/htmlRendererPropTypes';
import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
import {ShowContextMenuContext, showContextMenuForReport} from '@components/ShowContextMenuContext';
import withLocalize from '@components/withLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import * as ReportUtils from '@libs/ReportUtils';
import CONST from '@src/CONST';
+import htmlRendererPropTypes from './htmlRendererPropTypes';
const propTypes = {
/** Press in handler for the code block */
@@ -31,20 +31,14 @@ const defaultProps = {
onPressOut: undefined,
};
-const BasePreRenderer = forwardRef((props, ref) => {
+function PreRenderer(props) {
const styles = useThemeStyles();
const TDefaultRenderer = props.TDefaultRenderer;
const defaultRendererProps = _.omit(props, ['TDefaultRenderer', 'onPressIn', 'onPressOut', 'onLongPress']);
const isLast = props.renderIndex === props.renderLength - 1;
return (
-
+
{({anchor, report, action, checkIfContextMenuActive}) => (
{
)}
-
+
);
-});
+}
-BasePreRenderer.displayName = 'BasePreRenderer';
-BasePreRenderer.propTypes = propTypes;
-BasePreRenderer.defaultProps = defaultProps;
+PreRenderer.displayName = 'PreRenderer';
+PreRenderer.propTypes = propTypes;
+PreRenderer.defaultProps = defaultProps;
-export default withLocalize(BasePreRenderer);
+export default withLocalize(PreRenderer);
diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.js b/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.js
deleted file mode 100644
index 3beb52e6ee81..000000000000
--- a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import React, {useCallback, useEffect, useRef} from 'react';
-import _ from 'underscore';
-import htmlRendererPropTypes from '@components/HTMLEngineProvider/HTMLRenderers/htmlRendererPropTypes';
-import ControlSelection from '@libs/ControlSelection';
-import * as DeviceCapabilities from '@libs/DeviceCapabilities';
-import BasePreRenderer from './BasePreRenderer';
-
-const supportsPassive = DeviceCapabilities.hasPassiveEventListenerSupport();
-
-const isScrollingVertically = (event) =>
- // Mark as vertical scrolling only when absolute value of deltaY is more than the double of absolute
- // value of deltaX, so user can use trackpad scroll on the code block horizontally at a wide angle.
- Math.abs(event.deltaY) > Math.abs(event.deltaX) * 2;
-
-const debouncedIsScrollingVertically = _.debounce(isScrollingVertically, 100, true);
-
-function PreRenderer(props) {
- const scrollViewRef = useRef();
-
- /**
- * Checks if user is scrolling vertically based on deltaX and deltaY. We debounce this
- * method in order to make sure it's called only for the first event.
- * @param {WheelEvent} event Wheel event
- * @returns {Boolean} true if user is scrolling vertically
- */
-
- /**
- * Manually scrolls the code block if code block horizontal scrollable, then prevents the event from being passed up to the parent.
- * @param {Object} event native event
- */
- const scrollNode = useCallback((event) => {
- const node = scrollViewRef.current.getScrollableNode();
- const horizontalOverflow = node.scrollWidth > node.offsetWidth;
- if (event.currentTarget === node && horizontalOverflow && !debouncedIsScrollingVertically(event)) {
- node.scrollLeft += event.deltaX;
- }
- }, []);
-
- useEffect(() => {
- const eventListenerRefValue = scrollViewRef.current;
- if (!eventListenerRefValue) {
- return;
- }
- eventListenerRefValue.getScrollableNode().addEventListener('wheel', scrollNode, supportsPassive ? {passive: true} : false);
-
- return () => {
- if (!eventListenerRefValue.getScrollableNode()) {
- return;
- }
- eventListenerRefValue.getScrollableNode().removeEventListener('wheel', scrollNode);
- };
- }, [scrollNode]);
-
- return (
- DeviceCapabilities.canUseTouchScreen() && ControlSelection.block()}
- onPressOut={ControlSelection.unblock}
- />
- );
-}
-
-PreRenderer.propTypes = htmlRendererPropTypes;
-PreRenderer.displayName = 'PreRenderer';
-
-export default PreRenderer;
diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.native.js b/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.native.js
deleted file mode 100644
index b84dd43dd82f..000000000000
--- a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.native.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from 'react';
-import htmlRendererPropTypes from '@components/HTMLEngineProvider/HTMLRenderers/htmlRendererPropTypes';
-import withLocalize from '@components/withLocalize';
-import BasePreRenderer from './BasePreRenderer';
-
-function PreRenderer(props) {
- // eslint-disable-next-line react/jsx-props-no-spreading
- return ;
-}
-
-PreRenderer.propTypes = htmlRendererPropTypes;
-PreRenderer.displayName = 'PreRenderer';
-
-export default withLocalize(PreRenderer);
diff --git a/src/components/HTMLEngineProvider/htmlEnginePropTypes.js b/src/components/HTMLEngineProvider/htmlEnginePropTypes.js
deleted file mode 100644
index 6c8537c8d228..000000000000
--- a/src/components/HTMLEngineProvider/htmlEnginePropTypes.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import PropTypes from 'prop-types';
-
-const propTypes = {
- children: PropTypes.node,
-
- /** Optional debug flag. Prints the TRT in the console when true. */
- debug: PropTypes.bool,
-};
-
-const defaultProps = {
- children: null,
- debug: false,
-};
-
-export {propTypes, defaultProps};
diff --git a/src/components/HTMLEngineProvider/htmlEngineUtils.js b/src/components/HTMLEngineProvider/htmlEngineUtils.ts
similarity index 57%
rename from src/components/HTMLEngineProvider/htmlEngineUtils.js
rename to src/components/HTMLEngineProvider/htmlEngineUtils.ts
index 4495cb8ff136..5f082424a565 100644
--- a/src/components/HTMLEngineProvider/htmlEngineUtils.js
+++ b/src/components/HTMLEngineProvider/htmlEngineUtils.ts
@@ -1,4 +1,6 @@
-import lodashGet from 'lodash/get';
+import type {TNode} from 'react-native-render-html';
+
+type Predicate = (node: TNode) => boolean;
const MAX_IMG_DIMENSIONS = 512;
@@ -7,12 +9,12 @@ const MAX_IMG_DIMENSIONS = 512;
* is used by the HTML component in the default renderer for img tags to scale
* down images that would otherwise overflow horizontally.
*
- * @param {string} tagName - The name of the tag for which max width should be constrained.
- * @param {number} contentWidth - The content width provided to the HTML
+ * @param contentWidth - The content width provided to the HTML
* component.
- * @returns {number} The minimum between contentWidth and MAX_IMG_DIMENSIONS
+ * @param tagName - The name of the tag for which max width should be constrained.
+ * @returns The minimum between contentWidth and MAX_IMG_DIMENSIONS
*/
-function computeEmbeddedMaxWidth(tagName, contentWidth) {
+function computeEmbeddedMaxWidth(contentWidth: number, tagName: string): number {
if (tagName === 'img') {
return Math.min(MAX_IMG_DIMENSIONS, contentWidth);
}
@@ -22,21 +24,15 @@ function computeEmbeddedMaxWidth(tagName, contentWidth) {
/**
* Check if tagName is equal to any of our custom tags wrapping chat comments.
*
- * @param {string} tagName
- * @returns {Boolean}
*/
-function isCommentTag(tagName) {
+function isCommentTag(tagName: string): boolean {
return tagName === 'email-comment' || tagName === 'comment';
}
/**
* Check if there is an ancestor node for which the predicate returns true.
- *
- * @param {TNode} tnode
- * @param {Function} predicate
- * @returns {Boolean}
*/
-function isChildOfNode(tnode, predicate) {
+function isChildOfNode(tnode: TNode, predicate: Predicate): boolean {
let currentNode = tnode.parent;
while (currentNode) {
if (predicate(currentNode)) {
@@ -50,21 +46,17 @@ function isChildOfNode(tnode, predicate) {
/**
* Check if there is an ancestor node with name 'comment'.
* Finding node with name 'comment' flags that we are rendering a comment.
- * @param {TNode} tnode
- * @returns {Boolean}
*/
-function isChildOfComment(tnode) {
- return isChildOfNode(tnode, (node) => isCommentTag(lodashGet(node, 'domNode.name', '')));
+function isChildOfComment(tnode: TNode): boolean {
+ return isChildOfNode(tnode, (node) => node.domNode?.name !== undefined && isCommentTag(node.domNode.name));
}
/**
* Check if there is an ancestor node with the name 'h1'.
* Finding a node with the name 'h1' flags that we are rendering inside an h1 element.
- * @param {TNode} tnode
- * @returns {Boolean}
*/
-function isChildOfH1(tnode) {
- return isChildOfNode(tnode, (node) => lodashGet(node, 'domNode.name', '').toLowerCase() === 'h1');
+function isChildOfH1(tnode: TNode): boolean {
+ return isChildOfNode(tnode, (node) => node.domNode?.name !== undefined && node.domNode.name.toLowerCase() === 'h1');
}
export {computeEmbeddedMaxWidth, isChildOfComment, isCommentTag, isChildOfH1};
diff --git a/src/components/HTMLEngineProvider/index.js b/src/components/HTMLEngineProvider/index.js
deleted file mode 100755
index 8a8e96269411..000000000000
--- a/src/components/HTMLEngineProvider/index.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import React from 'react';
-import withWindowDimensions from '@components/withWindowDimensions';
-import * as DeviceCapabilities from '@libs/DeviceCapabilities';
-import BaseHTMLEngineProvider from './BaseHTMLEngineProvider';
-import {defaultProps, propTypes} from './htmlEnginePropTypes';
-
-function HTMLEngineProvider(props) {
- return (
-
- {props.children}
-
- );
-}
-
-HTMLEngineProvider.displayName = 'HTMLEngineProvider';
-HTMLEngineProvider.propTypes = propTypes;
-HTMLEngineProvider.defaultProps = defaultProps;
-
-export default withWindowDimensions(HTMLEngineProvider);
diff --git a/src/components/HTMLEngineProvider/index.native.js b/src/components/HTMLEngineProvider/index.native.js
deleted file mode 100755
index f760a5a36649..000000000000
--- a/src/components/HTMLEngineProvider/index.native.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import React from 'react';
-import BaseHTMLEngineProvider from './BaseHTMLEngineProvider';
-import {defaultProps, propTypes} from './htmlEnginePropTypes';
-
-function HTMLEngineProvider(props) {
- return (
-
- {props.children}
-
- );
-}
-
-HTMLEngineProvider.displayName = 'HTMLEngineProvider';
-HTMLEngineProvider.propTypes = propTypes;
-HTMLEngineProvider.defaultProps = defaultProps;
-
-export default HTMLEngineProvider;
diff --git a/src/components/HTMLEngineProvider/index.native.tsx b/src/components/HTMLEngineProvider/index.native.tsx
new file mode 100755
index 000000000000..c77bcaf7c5e3
--- /dev/null
+++ b/src/components/HTMLEngineProvider/index.native.tsx
@@ -0,0 +1,11 @@
+import React from 'react';
+import type ChildrenProps from '@src/types/utils/ChildrenProps';
+import BaseHTMLEngineProvider from './BaseHTMLEngineProvider';
+
+function HTMLEngineProvider({children}: ChildrenProps) {
+ return {children};
+}
+
+HTMLEngineProvider.displayName = 'HTMLEngineProvider';
+
+export default HTMLEngineProvider;
diff --git a/src/components/HTMLEngineProvider/index.tsx b/src/components/HTMLEngineProvider/index.tsx
new file mode 100755
index 000000000000..9addb549d13a
--- /dev/null
+++ b/src/components/HTMLEngineProvider/index.tsx
@@ -0,0 +1,15 @@
+import React from 'react';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import type ChildrenProps from '@src/types/utils/ChildrenProps';
+import BaseHTMLEngineProvider from './BaseHTMLEngineProvider';
+
+function HTMLEngineProvider({children}: ChildrenProps) {
+ const {isSmallScreenWidth} = useWindowDimensions();
+
+ return {children};
+}
+
+HTMLEngineProvider.displayName = 'HTMLEngineProvider';
+
+export default HTMLEngineProvider;
diff --git a/src/components/HeaderPageLayout.js b/src/components/HeaderPageLayout.tsx
similarity index 55%
rename from src/components/HeaderPageLayout.js
rename to src/components/HeaderPageLayout.tsx
index 9ef5d4f83a06..304bb2ce49b1 100644
--- a/src/components/HeaderPageLayout.js
+++ b/src/components/HeaderPageLayout.tsx
@@ -1,56 +1,54 @@
-import PropTypes from 'prop-types';
import React, {useMemo} from 'react';
+import type {ReactNode} from 'react';
import {ScrollView, View} from 'react-native';
-import _ from 'underscore';
+import type {StyleProp, ViewStyle} from 'react-native';
import useNetwork from '@hooks/useNetwork';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as Browser from '@libs/Browser';
+import type ChildrenProps from '@src/types/utils/ChildrenProps';
import FixedFooter from './FixedFooter';
import HeaderWithBackButton from './HeaderWithBackButton';
-import headerWithBackButtonPropTypes from './HeaderWithBackButton/headerWithBackButtonPropTypes';
+import type HeaderWithBackButtonProps from './HeaderWithBackButton/types';
import ScreenWrapper from './ScreenWrapper';
-const propTypes = {
- ...headerWithBackButtonPropTypes,
+type HeaderPageLayoutProps = ChildrenProps &
+ HeaderWithBackButtonProps & {
+ /** The background color to apply in the upper half of the screen. */
+ backgroundColor?: string;
- /** Children to display in the lower half of the page (below the header section w/ an animation) */
- children: PropTypes.node.isRequired,
+ /** A fixed footer to display at the bottom of the page. */
+ footer?: ReactNode;
- /** The background color to apply in the upper half of the screen. */
- backgroundColor: PropTypes.string,
+ /** The image to display in the upper half of the screen. */
+ headerContent?: ReactNode;
- /** A fixed footer to display at the bottom of the page. */
- footer: PropTypes.node,
+ /** Style to apply to the header image container */
+ headerContainerStyles?: StyleProp;
- /** The image to display in the upper half of the screen. */
- header: PropTypes.node,
+ /** Style to apply to the ScrollView container */
+ scrollViewContainerStyles?: StyleProp;
- /** Style to apply to the header image container */
- // eslint-disable-next-line react/forbid-prop-types
- headerContainerStyles: PropTypes.arrayOf(PropTypes.object),
+ /** Style to apply to the children container */
+ childrenContainerStyles?: StyleProp;
- /** Style to apply to the ScrollView container */
- // eslint-disable-next-line react/forbid-prop-types
- scrollViewContainerStyles: PropTypes.arrayOf(PropTypes.object),
+ /** Style to apply to the whole section container */
+ style?: StyleProp;
+ };
- /** Style to apply to the children container */
- // eslint-disable-next-line react/forbid-prop-types
- childrenContainerStyles: PropTypes.arrayOf(PropTypes.object),
-};
-
-const defaultProps = {
- backgroundColor: undefined,
- header: null,
- headerContainerStyles: [],
- scrollViewContainerStyles: [],
- childrenContainerStyles: [],
- footer: null,
-};
-
-function HeaderPageLayout({backgroundColor, children, footer, headerContainerStyles, scrollViewContainerStyles, childrenContainerStyles, style, headerContent, ...propsToPassToHeader}) {
+function HeaderPageLayout({
+ backgroundColor,
+ children,
+ footer,
+ headerContainerStyles,
+ scrollViewContainerStyles,
+ childrenContainerStyles,
+ style,
+ headerContent,
+ ...rest
+}: HeaderPageLayoutProps) {
const theme = useTheme();
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
@@ -58,7 +56,7 @@ function HeaderPageLayout({backgroundColor, children, footer, headerContainerSty
const {isOffline} = useNetwork();
const appBGColor = StyleUtils.getBackgroundColorStyle(theme.appBG);
const {titleColor, iconFill} = useMemo(() => {
- const isColorfulBackground = (backgroundColor || theme.appBG) !== theme.appBG && (backgroundColor || theme.highlightBG) !== theme.highlightBG;
+ const isColorfulBackground = (backgroundColor ?? theme.appBG) !== theme.appBG && (backgroundColor ?? theme.highlightBG) !== theme.highlightBG;
return {
titleColor: isColorfulBackground ? theme.textColorfulBackground : undefined,
iconFill: isColorfulBackground ? theme.iconColorfulBackground : undefined,
@@ -67,7 +65,7 @@ function HeaderPageLayout({backgroundColor, children, footer, headerContainerSty
return (
-
+
{/** Safari on ios/mac has a bug where overscrolling the page scrollview shows green background color. This is a workaround to fix that. https://github.com/Expensify/App/issues/23422 */}
{Browser.isSafari() && (
-
+
)}
-
- {!Browser.isSafari() && }
-
+
+ {!Browser.isSafari() && }
+
{headerContent}
{children}
- {!_.isNull(footer) && {footer}}
+ {!!footer && {footer}}
>
)}
@@ -107,8 +102,7 @@ function HeaderPageLayout({backgroundColor, children, footer, headerContainerSty
);
}
-HeaderPageLayout.propTypes = propTypes;
-HeaderPageLayout.defaultProps = defaultProps;
HeaderPageLayout.displayName = 'HeaderPageLayout';
+export type {HeaderPageLayoutProps};
export default HeaderPageLayout;
diff --git a/src/components/HeaderWithBackButton/index.tsx b/src/components/HeaderWithBackButton/index.tsx
index 209803f2a5d1..6cbfde0645de 100755
--- a/src/components/HeaderWithBackButton/index.tsx
+++ b/src/components/HeaderWithBackButton/index.tsx
@@ -61,7 +61,6 @@ function HeaderWithBackButton({
const StyleUtils = useStyleUtils();
const [isDownloadButtonActive, temporarilyDisableDownloadButton] = useThrottledButtonState();
const {translate} = useLocalize();
- // @ts-expect-error TODO: Remove this once useKeyboardState (https://github.com/Expensify/App/issues/24941) is migrated to TypeScript.
const {isKeyboardShown} = useKeyboardState();
const waitForNavigate = useWaitForNavigation();
diff --git a/src/components/HoldMenuSectionList.tsx b/src/components/HoldMenuSectionList.tsx
new file mode 100644
index 000000000000..aa5dd75ce159
--- /dev/null
+++ b/src/components/HoldMenuSectionList.tsx
@@ -0,0 +1,79 @@
+import React from 'react';
+import {View} from 'react-native';
+import type {ImageSourcePropType} from 'react-native';
+import type {SvgProps} from 'react-native-svg';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import variables from '@styles/variables';
+import type {TranslationPaths} from '@src/languages/types';
+import Icon from './Icon';
+import * as Illustrations from './Icon/Illustrations';
+import Text from './Text';
+
+type HoldMenuSection = {
+ /** The icon supplied with the section */
+ icon: React.FC | ImageSourcePropType;
+
+ /** Translation key for the title */
+ titleTranslationKey: TranslationPaths;
+
+ /** Translation key for the description */
+ descriptionTranslationKey: TranslationPaths;
+};
+
+function HoldMenuSectionList() {
+ const {translate} = useLocalize();
+ const styles = useThemeStyles();
+
+ const holdMenuSections: HoldMenuSection[] = [
+ {
+ icon: Illustrations.Hourglass,
+ titleTranslationKey: 'iou.whatIsHoldTitle',
+ descriptionTranslationKey: 'iou.whatIsHoldExplain',
+ },
+ {
+ icon: Illustrations.CommentBubbles,
+ titleTranslationKey: 'iou.holdIsTemporaryTitle',
+ descriptionTranslationKey: 'iou.holdIsTemporaryExplain',
+ },
+ {
+ icon: Illustrations.TrashCan,
+ titleTranslationKey: 'iou.deleteHoldTitle',
+ descriptionTranslationKey: 'iou.deleteHoldExplain',
+ },
+ ];
+
+ return (
+ <>
+ {holdMenuSections.map((section, i) => (
+
+
+
+ {translate(section.titleTranslationKey)}
+
+ {translate(section.descriptionTranslationKey)}
+
+
+
+ ))}
+ >
+ );
+}
+
+HoldMenuSectionList.displayName = 'HoldMenuSectionList';
+
+export type {HoldMenuSection};
+
+export default HoldMenuSectionList;
diff --git a/src/components/Hoverable/ActiveHoverable.tsx b/src/components/Hoverable/ActiveHoverable.tsx
new file mode 100644
index 000000000000..028fdd30cf35
--- /dev/null
+++ b/src/components/Hoverable/ActiveHoverable.tsx
@@ -0,0 +1,127 @@
+import type {Ref} from 'react';
+import {cloneElement, forwardRef, useCallback, useEffect, useMemo, useRef, useState} from 'react';
+import {DeviceEventEmitter} from 'react-native';
+import mergeRefs from '@libs/mergeRefs';
+import {getReturnValue} from '@libs/ValueUtils';
+import CONST from '@src/CONST';
+import type HoverableProps from './types';
+
+type ActiveHoverableProps = Omit;
+
+function ActiveHoverable({onHoverIn, onHoverOut, shouldHandleScroll, children}: ActiveHoverableProps, outerRef: Ref) {
+ const [isHovered, setIsHovered] = useState(false);
+
+ const elementRef = useRef(null);
+ const isScrollingRef = useRef(false);
+ const isHoveredRef = useRef(false);
+
+ const updateIsHovered = useCallback(
+ (hovered: boolean) => {
+ isHoveredRef.current = hovered;
+ if (shouldHandleScroll && isScrollingRef.current) {
+ return;
+ }
+ setIsHovered(hovered);
+ },
+ [shouldHandleScroll],
+ );
+
+ useEffect(() => {
+ if (isHovered) {
+ onHoverIn?.();
+ } else {
+ onHoverOut?.();
+ }
+ }, [isHovered, onHoverIn, onHoverOut]);
+
+ useEffect(() => {
+ if (!shouldHandleScroll) {
+ return;
+ }
+
+ const scrollingListener = DeviceEventEmitter.addListener(CONST.EVENTS.SCROLLING, (scrolling) => {
+ isScrollingRef.current = scrolling;
+ if (!isScrollingRef.current) {
+ setIsHovered(isHoveredRef.current);
+ }
+ });
+
+ return () => scrollingListener.remove();
+ }, [shouldHandleScroll]);
+
+ useEffect(() => {
+ // Do not mount a listener if the component is not hovered
+ if (!isHovered) {
+ return;
+ }
+
+ /**
+ * Checks the hover state of a component and updates it based on the event target.
+ * This is necessary to handle cases where the hover state might get stuck due to an unreliable mouseleave trigger,
+ * such as when an element is removed before the mouseleave event is triggered.
+ * @param event The hover event object.
+ */
+ const unsetHoveredIfOutside = (event: MouseEvent) => {
+ if (!elementRef.current || elementRef.current.contains(event.target as Node)) {
+ return;
+ }
+
+ setIsHovered(false);
+ };
+
+ document.addEventListener('mouseover', unsetHoveredIfOutside);
+
+ return () => document.removeEventListener('mouseover', unsetHoveredIfOutside);
+ }, [isHovered, elementRef]);
+
+ useEffect(() => {
+ const unsetHoveredWhenDocumentIsHidden = () => document.visibilityState === 'hidden' && setIsHovered(false);
+
+ document.addEventListener('visibilitychange', unsetHoveredWhenDocumentIsHidden);
+
+ return () => document.removeEventListener('visibilitychange', unsetHoveredWhenDocumentIsHidden);
+ }, []);
+
+ const child = useMemo(() => getReturnValue(children, !isScrollingRef.current && isHovered), [children, isHovered]);
+
+ const childOnMouseEnter = child.props.onMouseEnter;
+ const childOnMouseLeave = child.props.onMouseLeave;
+
+ const hoverAndForwardOnMouseEnter = useCallback(
+ (e: MouseEvent) => {
+ updateIsHovered(true);
+ childOnMouseEnter?.(e);
+ },
+ [updateIsHovered, childOnMouseEnter],
+ );
+
+ const unhoverAndForwardOnMouseLeave = useCallback(
+ (e: MouseEvent) => {
+ updateIsHovered(false);
+ childOnMouseLeave?.(e);
+ },
+ [updateIsHovered, childOnMouseLeave],
+ );
+
+ const unhoverAndForwardOnBlur = useCallback(
+ (event: MouseEvent) => {
+ // Check if the blur event occurred due to clicking outside the element
+ // and the wrapperView contains the element that caused the blur and reset isHovered
+ if (!elementRef.current?.contains(event.target as Node) && !elementRef.current?.contains(event.relatedTarget as Node)) {
+ setIsHovered(false);
+ }
+
+ child.props.onBlur?.(event);
+ },
+ [child.props],
+ );
+
+ return cloneElement(child, {
+ ref: mergeRefs(elementRef, outerRef, child.ref),
+ onMouseEnter: hoverAndForwardOnMouseEnter,
+ onMouseLeave: unhoverAndForwardOnMouseLeave,
+ onBlur: unhoverAndForwardOnBlur,
+ });
+}
+
+export default forwardRef(ActiveHoverable);
diff --git a/src/components/Hoverable/index.tsx b/src/components/Hoverable/index.tsx
index c82ba659593a..3729ee380b34 100644
--- a/src/components/Hoverable/index.tsx
+++ b/src/components/Hoverable/index.tsx
@@ -1,213 +1,29 @@
-import type {ForwardedRef, MutableRefObject, ReactElement, RefAttributes} from 'react';
-import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react';
-import {DeviceEventEmitter} from 'react-native';
-import * as DeviceCapabilities from '@libs/DeviceCapabilities';
-import CONST from '@src/CONST';
+import type {Ref} from 'react';
+import React, {cloneElement, forwardRef} from 'react';
+import {hasHoverSupport} from '@libs/DeviceCapabilities';
+import {getReturnValue} from '@libs/ValueUtils';
+import ActiveHoverable from './ActiveHoverable';
import type HoverableProps from './types';
-/**
- * Maps the children of a Hoverable component to
- * - a function that is called with the parameter
- * - the child itself if it is the only child
- * @param children The children to map.
- * @param callbackParam The parameter to pass to the children function.
- * @returns The mapped children.
- */
-function mapChildren(children: ((isHovered: boolean) => ReactElement) | ReactElement | ReactElement[], callbackParam: boolean): ReactElement & RefAttributes {
- if (Array.isArray(children)) {
- return children[0];
- }
-
- if (typeof children === 'function') {
- return children(callbackParam);
- }
-
- return children;
-}
-
-/**
- * Assigns a ref to an element, either by setting the current property of the ref object or by calling the ref function
- * @param ref The ref object or function.
- * @param element The element to assign the ref to.
- */
-function assignRef(ref: ((instance: HTMLElement | null) => void) | MutableRefObject, element: HTMLElement) {
- if (!ref) {
- return;
- }
- if (typeof ref === 'function') {
- ref(element);
- } else if ('current' in ref) {
- // eslint-disable-next-line no-param-reassign
- ref.current = element;
- }
-}
-
/**
* It is necessary to create a Hoverable component instead of relying solely on Pressable support for hover state,
* because nesting Pressables causes issues where the hovered state of the child cannot be easily propagated to the
* parent. https://github.com/necolas/react-native-web/issues/1875
*/
-function Hoverable(
- {disabled = false, onHoverIn = () => {}, onHoverOut = () => {}, onMouseEnter = () => {}, onMouseLeave = () => {}, children, shouldHandleScroll = false}: HoverableProps,
- outerRef: ForwardedRef,
-) {
- const [isHovered, setIsHovered] = useState(false);
-
- const isScrolling = useRef(false);
- const isHoveredRef = useRef(false);
- const ref = useRef(null);
-
- const updateIsHoveredOnScrolling = useCallback(
- (hovered: boolean) => {
- if (disabled) {
- return;
- }
-
- isHoveredRef.current = hovered;
-
- if (shouldHandleScroll && isScrolling.current) {
- return;
- }
- setIsHovered(hovered);
- },
- [disabled, shouldHandleScroll],
- );
-
- useEffect(() => {
- const unsetHoveredWhenDocumentIsHidden = () => document.visibilityState === 'hidden' && setIsHovered(false);
-
- document.addEventListener('visibilitychange', unsetHoveredWhenDocumentIsHidden);
-
- return () => document.removeEventListener('visibilitychange', unsetHoveredWhenDocumentIsHidden);
- }, []);
-
- useEffect(() => {
- if (!shouldHandleScroll) {
- return;
- }
-
- const scrollingListener = DeviceEventEmitter.addListener(CONST.EVENTS.SCROLLING, (scrolling) => {
- isScrolling.current = scrolling;
- if (!scrolling) {
- setIsHovered(isHoveredRef.current);
- }
- });
-
- return () => scrollingListener.remove();
- }, [shouldHandleScroll]);
-
- useEffect(() => {
- if (!DeviceCapabilities.hasHoverSupport()) {
- return;
- }
-
- /**
- * Checks the hover state of a component and updates it based on the event target.
- * This is necessary to handle cases where the hover state might get stuck due to an unreliable mouseleave trigger,
- * such as when an element is removed before the mouseleave event is triggered.
- * @param event The hover event object.
- */
- const unsetHoveredIfOutside = (event: MouseEvent) => {
- if (!ref.current || !isHovered) {
- return;
- }
-
- if (ref.current.contains(event.target as Node)) {
- return;
- }
-
- setIsHovered(false);
- };
-
- document.addEventListener('mouseover', unsetHoveredIfOutside);
-
- return () => document.removeEventListener('mouseover', unsetHoveredIfOutside);
- }, [isHovered]);
-
- useEffect(() => {
- if (!disabled || !isHovered) {
- return;
- }
- setIsHovered(false);
- }, [disabled, isHovered]);
-
- useEffect(() => {
- if (disabled) {
- return;
- }
- if (onHoverIn && isHovered) {
- return onHoverIn();
- }
- if (onHoverOut && !isHovered) {
- return onHoverOut();
- }
- }, [disabled, isHovered, onHoverIn, onHoverOut]);
-
- // Expose inner ref to parent through outerRef. This enable us to use ref both in parent and child.
- useImperativeHandle(outerRef, () => ref.current, []);
-
- const child = useMemo(() => React.Children.only(mapChildren(children as ReactElement, isHovered)), [children, isHovered]);
-
- const enableHoveredOnMouseEnter = useCallback(
- (event: MouseEvent) => {
- updateIsHoveredOnScrolling(true);
- onMouseEnter(event);
-
- if (typeof child.props.onMouseEnter === 'function') {
- child.props.onMouseEnter(event);
- }
- },
- [child.props, onMouseEnter, updateIsHoveredOnScrolling],
- );
-
- const disableHoveredOnMouseLeave = useCallback(
- (event: MouseEvent) => {
- updateIsHoveredOnScrolling(false);
- onMouseLeave(event);
-
- if (typeof child.props.onMouseLeave === 'function') {
- child.props.onMouseLeave(event);
- }
- },
- [child.props, onMouseLeave, updateIsHoveredOnScrolling],
- );
-
- const disableHoveredOnBlur = useCallback(
- (event: MouseEvent) => {
- // Check if the blur event occurred due to clicking outside the element
- // and the wrapperView contains the element that caused the blur and reset isHovered
- if (!ref.current?.contains(event.target as Node) && !ref.current?.contains(event.relatedTarget as Node)) {
- setIsHovered(false);
- }
-
- if (typeof child.props.onBlur === 'function') {
- child.props.onBlur(event);
- }
- },
- [child.props],
- );
-
- // We need to access the ref of a children from both parent and current component
- // So we pass it to current ref and assign it once again to the child ref prop
- const hijackRef = (el: HTMLElement) => {
- ref.current = el;
- if (child.ref) {
- assignRef(child.ref, el);
- }
- };
-
- if (!DeviceCapabilities.hasHoverSupport()) {
- return React.cloneElement(child, {
- ref: hijackRef,
- });
+function Hoverable({isDisabled, ...props}: HoverableProps, ref: Ref) {
+ // If Hoverable is disabled, just render the child without additional logic or event listeners.
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
+ if (isDisabled || !hasHoverSupport()) {
+ return cloneElement(getReturnValue(props.children, false), {ref});
}
- return React.cloneElement(child, {
- ref: hijackRef,
- onMouseEnter: enableHoveredOnMouseEnter,
- onMouseLeave: disableHoveredOnMouseLeave,
- onBlur: disableHoveredOnBlur,
- });
+ return (
+
+ );
}
export default forwardRef(Hoverable);
diff --git a/src/components/Hoverable/types.ts b/src/components/Hoverable/types.ts
index 921772743ab4..6963e3b5178c 100644
--- a/src/components/Hoverable/types.ts
+++ b/src/components/Hoverable/types.ts
@@ -1,11 +1,14 @@
-import type {ReactNode} from 'react';
+import type {ReactElement, RefAttributes} from 'react';
+
+type HoverableChild = ReactElement & RefAttributes;
+type HoverableChildren = ((isHovered: boolean) => HoverableChild) | HoverableChild;
type HoverableProps = {
/** Children to wrap with Hoverable. */
- children: ((isHovered: boolean) => ReactNode) | ReactNode;
+ children: HoverableChildren;
/** Whether to disable the hover action */
- disabled?: boolean;
+ isDisabled?: boolean;
/** Function that executes when the mouse moves over the children. */
onHoverIn?: () => void;
@@ -13,14 +16,10 @@ type HoverableProps = {
/** Function that executes when the mouse leaves the children. */
onHoverOut?: () => void;
- /** Direct pass-through of React's onMouseEnter event. */
- onMouseEnter?: (event: MouseEvent) => void;
-
- /** Direct pass-through of React's onMouseLeave event. */
- onMouseLeave?: (event: MouseEvent) => void;
-
/** Decides whether to handle the scroll behaviour to show hover once the scroll ends */
shouldHandleScroll?: boolean;
};
export default HoverableProps;
+
+export type {HoverableChild};
diff --git a/src/components/Icon/Illustrations.ts b/src/components/Icon/Illustrations.ts
index 1e574504001d..954c8d0392fc 100644
--- a/src/components/Icon/Illustrations.ts
+++ b/src/components/Icon/Illustrations.ts
@@ -32,6 +32,7 @@ import BigRocket from '@assets/images/simple-illustrations/simple-illustration__
import PinkBill from '@assets/images/simple-illustrations/simple-illustration__bill.svg';
import ChatBubbles from '@assets/images/simple-illustrations/simple-illustration__chatbubbles.svg';
import CoffeeMug from '@assets/images/simple-illustrations/simple-illustration__coffeemug.svg';
+import CommentBubbles from '@assets/images/simple-illustrations/simple-illustration__commentbubbles.svg';
import ConciergeBubble from '@assets/images/simple-illustrations/simple-illustration__concierge-bubble.svg';
import ConciergeNew from '@assets/images/simple-illustrations/simple-illustration__concierge.svg';
import CreditCardsNew from '@assets/images/simple-illustrations/simple-illustration__credit-cards.svg';
@@ -39,6 +40,7 @@ import EmailAddress from '@assets/images/simple-illustrations/simple-illustratio
import HandCard from '@assets/images/simple-illustrations/simple-illustration__handcard.svg';
import HandEarth from '@assets/images/simple-illustrations/simple-illustration__handearth.svg';
import HotDogStand from '@assets/images/simple-illustrations/simple-illustration__hotdogstand.svg';
+import Hourglass from '@assets/images/simple-illustrations/simple-illustration__hourglass.svg';
import InvoiceBlue from '@assets/images/simple-illustrations/simple-illustration__invoice.svg';
import LockOpen from '@assets/images/simple-illustrations/simple-illustration__lockopen.svg';
import Luggage from '@assets/images/simple-illustrations/simple-illustration__luggage.svg';
@@ -53,6 +55,7 @@ import ShieldYellow from '@assets/images/simple-illustrations/simple-illustratio
import SmallRocket from '@assets/images/simple-illustrations/simple-illustration__smallrocket.svg';
import ThumbsUpStars from '@assets/images/simple-illustrations/simple-illustration__thumbsupstars.svg';
import TrackShoe from '@assets/images/simple-illustrations/simple-illustration__track-shoe.svg';
+import TrashCan from '@assets/images/simple-illustrations/simple-illustration__trashcan.svg';
import TreasureChest from '@assets/images/simple-illustrations/simple-illustration__treasurechest.svg';
export {
@@ -111,5 +114,8 @@ export {
Hands,
HandEarth,
SmartScan,
+ Hourglass,
+ CommentBubbles,
+ TrashCan,
TeleScope,
};
diff --git a/src/components/IllustratedHeaderPageLayout.js b/src/components/IllustratedHeaderPageLayout.js
deleted file mode 100644
index 9980d8a7879a..000000000000
--- a/src/components/IllustratedHeaderPageLayout.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import useTheme from '@hooks/useTheme';
-import useThemeStyles from '@hooks/useThemeStyles';
-import HeaderPageLayout from './HeaderPageLayout';
-import headerWithBackButtonPropTypes from './HeaderWithBackButton/headerWithBackButtonPropTypes';
-import Lottie from './Lottie';
-
-const propTypes = {
- ...headerWithBackButtonPropTypes,
-
- /** Children to display in the lower half of the page (below the header section w/ an animation) */
- children: PropTypes.node.isRequired,
-
- /** The illustration to display in the header. Can be either an SVG component or a JSON object representing a Lottie animation. */
- illustration: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired,
-
- /** The background color to apply in the upper half of the screen. */
- backgroundColor: PropTypes.string,
-
- /** A fixed footer to display at the bottom of the page. */
- footer: PropTypes.node,
-
- /** Overlay content to display on top of animation */
- overlayContent: PropTypes.func,
-};
-
-const defaultProps = {
- backgroundColor: undefined,
- footer: null,
- overlayContent: null,
-};
-
-function IllustratedHeaderPageLayout({backgroundColor, children, illustration, footer, overlayContent, ...propsToPassToHeader}) {
- const theme = useTheme();
- const styles = useThemeStyles();
- return (
-
-
- {overlayContent && overlayContent()}
- >
- }
- headerContainerStyles={[styles.justifyContentCenter, styles.w100]}
- footer={footer}
- // eslint-disable-next-line react/jsx-props-no-spreading
- {...propsToPassToHeader}
- >
- {children}
-
- );
-}
-
-IllustratedHeaderPageLayout.propTypes = propTypes;
-IllustratedHeaderPageLayout.defaultProps = defaultProps;
-IllustratedHeaderPageLayout.displayName = 'IllustratedHeaderPageLayout';
-
-export default IllustratedHeaderPageLayout;
diff --git a/src/components/IllustratedHeaderPageLayout.tsx b/src/components/IllustratedHeaderPageLayout.tsx
new file mode 100644
index 000000000000..72ec0adf7672
--- /dev/null
+++ b/src/components/IllustratedHeaderPageLayout.tsx
@@ -0,0 +1,50 @@
+import React from 'react';
+import type {ReactNode} from 'react';
+import useTheme from '@hooks/useTheme';
+import useThemeStyles from '@hooks/useThemeStyles';
+import HeaderPageLayout from './HeaderPageLayout';
+import type {HeaderPageLayoutProps} from './HeaderPageLayout';
+import Lottie from './Lottie';
+import type DotLottieAnimation from './LottieAnimations/types';
+
+type IllustratedHeaderPageLayoutProps = HeaderPageLayoutProps & {
+ /** The illustration to display in the header. Can be a JSON object representing a Lottie animation. */
+ illustration: DotLottieAnimation;
+
+ /** The background color to apply in the upper half of the screen. */
+ backgroundColor?: string;
+
+ /** Overlay content to display on top of animation */
+ overlayContent?: () => ReactNode;
+};
+
+function IllustratedHeaderPageLayout({backgroundColor, children, illustration, overlayContent, ...rest}: IllustratedHeaderPageLayoutProps) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
+ return (
+
+
+ {overlayContent?.()}
+ >
+ }
+ headerContainerStyles={[styles.justifyContentCenter, styles.w100]}
+ // eslint-disable-next-line react/jsx-props-no-spreading
+ {...rest}
+ >
+ {children}
+
+ );
+}
+
+IllustratedHeaderPageLayout.displayName = 'IllustratedHeaderPageLayout';
+
+export default IllustratedHeaderPageLayout;
diff --git a/src/components/InvertedFlatList/BaseInvertedFlatList.tsx b/src/components/InvertedFlatList/BaseInvertedFlatList.tsx
index 9e3991828625..e28400505280 100644
--- a/src/components/InvertedFlatList/BaseInvertedFlatList.tsx
+++ b/src/components/InvertedFlatList/BaseInvertedFlatList.tsx
@@ -3,8 +3,8 @@ import React, {forwardRef} from 'react';
import type {FlatListProps} from 'react-native';
import FlatList from '@components/FlatList';
-const AUTOSCROLL_TO_TOP_THRESHOLD = 128;
const WINDOW_SIZE = 15;
+const AUTOSCROLL_TO_TOP_THRESHOLD = 128;
function BaseInvertedFlatList(props: FlatListProps, ref: ForwardedRef) {
return (
diff --git a/src/components/InvertedFlatList/index.native.tsx b/src/components/InvertedFlatList/index.native.tsx
index 76c4b774d0cc..70cabf5a536a 100644
--- a/src/components/InvertedFlatList/index.native.tsx
+++ b/src/components/InvertedFlatList/index.native.tsx
@@ -1,18 +1,15 @@
import type {ForwardedRef} from 'react';
import React, {forwardRef} from 'react';
import type {FlatList, FlatListProps} from 'react-native';
-import useThemeStyles from '@hooks/useThemeStyles';
import BaseInvertedFlatList from './BaseInvertedFlatList';
import CellRendererComponent from './CellRendererComponent';
function BaseInvertedFlatListWithRef(props: FlatListProps, ref: ForwardedRef) {
- const styles = useThemeStyles();
return (
({onScroll: onScrollProp = () => {}, contentContainerStyle, ...props}: FlatListProps, ref: ForwardedRef) {
+function InvertedFlatList({onScroll: onScrollProp = () => {}, ...props}: FlatListProps, ref: ForwardedRef) {
const lastScrollEvent = useRef(null);
const scrollEndTimeout = useRef(null);
const updateInProgress = useRef(false);
@@ -86,8 +87,8 @@ function InvertedFlatList({onScroll: onScrollProp = () => {}, contentContaine
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
ref={ref}
- contentContainerStyle={contentContainerStyle}
onScroll={handleScroll}
+ CellRendererComponent={CellRendererComponent}
/>
);
}
diff --git a/src/components/Lightbox.js b/src/components/Lightbox.js
index 06f8ee4cfeb6..45326edb4610 100644
--- a/src/components/Lightbox.js
+++ b/src/components/Lightbox.js
@@ -183,8 +183,8 @@ function Lightbox({isAuthTokenRequired, source, onScaleChanged, onPress, onError
onError={onError}
onLoadEnd={() => setImageLoaded(true)}
onLoad={(e) => {
- const width = (e.nativeEvent?.width || 0) / PixelRatio.get();
- const height = (e.nativeEvent?.height || 0) / PixelRatio.get();
+ const width = (e.nativeEvent?.width || 0) * PixelRatio.get();
+ const height = (e.nativeEvent?.height || 0) * PixelRatio.get();
setImageDimensions({...imageDimensions, lightboxSize: {width, height}});
}}
/>
@@ -205,8 +205,8 @@ function Lightbox({isAuthTokenRequired, source, onScaleChanged, onPress, onError
isAuthTokenRequired={isAuthTokenRequired}
onLoadEnd={() => setFallbackLoaded(true)}
onLoad={(e) => {
- const width = e.nativeEvent?.width || 0;
- const height = e.nativeEvent?.height || 0;
+ const width = (e.nativeEvent?.width || 0) * PixelRatio.get();
+ const height = (e.nativeEvent?.height || 0) * PixelRatio.get();
if (imageDimensions?.lightboxSize != null) {
return;
diff --git a/src/components/LottieAnimations/index.tsx b/src/components/LottieAnimations/index.tsx
index 0d2cac253135..d42d471eba5e 100644
--- a/src/components/LottieAnimations/index.tsx
+++ b/src/components/LottieAnimations/index.tsx
@@ -51,6 +51,11 @@ const DotLottieAnimations: Record = {
w: 853,
h: 480,
},
+ Coin: {
+ file: require('@assets/animations/Coin.lottie'),
+ w: 375,
+ h: 240,
+ },
};
export default DotLottieAnimations;
diff --git a/src/components/MapView/MapView.tsx b/src/components/MapView/MapView.tsx
index 6321b461f21e..a3178f642852 100644
--- a/src/components/MapView/MapView.tsx
+++ b/src/components/MapView/MapView.tsx
@@ -105,7 +105,7 @@ const MapView = forwardRef(
if (waypoints.length === 1) {
cameraRef.current?.setCamera({
- zoomLevel: 15,
+ zoomLevel: CONST.MAPBOX.SINGLE_MARKER_ZOOM,
animationDuration: 1500,
centerCoordinate: waypoints[0].coordinate,
});
diff --git a/src/components/MapView/MapView.website.tsx b/src/components/MapView/MapView.website.tsx
index 05d86e8ec999..289f7d0d62a8 100644
--- a/src/components/MapView/MapView.website.tsx
+++ b/src/components/MapView/MapView.website.tsx
@@ -117,7 +117,7 @@ const MapView = forwardRef(
if (waypoints.length === 1) {
mapRef.flyTo({
center: waypoints[0].coordinate,
- zoom: CONST.MAPBOX.DEFAULT_ZOOM,
+ zoom: CONST.MAPBOX.SINGLE_MARKER_ZOOM,
});
return;
}
diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx
index 14dfd0e8dbc4..334fa9895205 100644
--- a/src/components/MenuItem.tsx
+++ b/src/components/MenuItem.tsx
@@ -35,20 +35,6 @@ import RenderHTML from './RenderHTML';
import SelectCircle from './SelectCircle';
import Text from './Text';
-type ResponsiveProps = {
- /** Function to fire when component is pressed */
- onPress: (event: GestureResponderEvent | KeyboardEvent) => void;
-
- interactive?: true;
-};
-
-type UnresponsiveProps = {
- onPress?: undefined;
-
- /** Whether the menu item should be interactive at all */
- interactive: false;
-};
-
type IconProps = {
/** Flag to choose between avatar image or an icon */
iconType?: typeof CONST.ICON_TYPE_ICON;
@@ -69,170 +55,175 @@ type NoIcon = {
icon?: undefined;
};
-type MenuItemProps = (ResponsiveProps | UnresponsiveProps) &
- (IconProps | AvatarProps | NoIcon) & {
- /** Text to be shown as badge near the right end. */
- badgeText?: string;
+type MenuItemProps = (IconProps | AvatarProps | NoIcon) & {
+ /** Function to fire when component is pressed */
+ onPress?: (event: GestureResponderEvent | KeyboardEvent) => void;
+
+ /** Whether the menu item should be interactive at all */
+ interactive?: boolean;
- /** Used to apply offline styles to child text components */
- style?: ViewStyle;
+ /** Text to be shown as badge near the right end. */
+ badgeText?: string;
- /** Any additional styles to apply */
- wrapperStyle?: StyleProp;
+ /** Used to apply offline styles to child text components */
+ style?: StyleProp;
- /** Any additional styles to apply on the outer element */
- containerStyle?: StyleProp;
+ /** Any additional styles to apply */
+ wrapperStyle?: StyleProp;
- /** Used to apply styles specifically to the title */
- titleStyle?: ViewStyle;
+ /** Any additional styles to apply on the outer element */
+ containerStyle?: StyleProp;
- /** Any adjustments to style when menu item is hovered or pressed */
- hoverAndPressStyle?: StyleProp>;
+ /** Used to apply styles specifically to the title */
+ titleStyle?: ViewStyle;
- /** Additional styles to style the description text below the title */
- descriptionTextStyle?: StyleProp;
+ /** Any adjustments to style when menu item is hovered or pressed */
+ hoverAndPressStyle?: StyleProp>;
- /** The fill color to pass into the icon. */
- iconFill?: string;
+ /** Additional styles to style the description text below the title */
+ descriptionTextStyle?: StyleProp;
- /** Secondary icon to display on the left side of component, right of the icon */
- secondaryIcon?: IconAsset;
+ /** The fill color to pass into the icon. */
+ iconFill?: string;
- /** The fill color to pass into the secondary icon. */
- secondaryIconFill?: string;
+ /** Secondary icon to display on the left side of component, right of the icon */
+ secondaryIcon?: IconAsset;
- /** Icon Width */
- iconWidth?: number;
+ /** The fill color to pass into the secondary icon. */
+ secondaryIconFill?: string;
- /** Icon Height */
- iconHeight?: number;
+ /** Icon Width */
+ iconWidth?: number;
- /** Any additional styles to pass to the icon container. */
- iconStyles?: StyleProp;
+ /** Icon Height */
+ iconHeight?: number;
- /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */
- fallbackIcon?: IconAsset;
+ /** Any additional styles to pass to the icon container. */
+ iconStyles?: StyleProp;
- /** An icon to display under the main item */
- furtherDetailsIcon?: IconAsset;
+ /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */
+ fallbackIcon?: IconAsset;
- /** Boolean whether to display the title right icon */
- shouldShowTitleIcon?: boolean;
+ /** An icon to display under the main item */
+ furtherDetailsIcon?: IconAsset;
- /** Icon to display at right side of title */
- titleIcon?: IconAsset;
+ /** Boolean whether to display the title right icon */
+ shouldShowTitleIcon?: boolean;
- /** Boolean whether to display the right icon */
- shouldShowRightIcon?: boolean;
+ /** Icon to display at right side of title */
+ titleIcon?: IconAsset;
- /** Overrides the icon for shouldShowRightIcon */
- iconRight?: IconAsset;
+ /** Boolean whether to display the right icon */
+ shouldShowRightIcon?: boolean;
- /** Should render component on the right */
- shouldShowRightComponent?: boolean;
+ /** Overrides the icon for shouldShowRightIcon */
+ iconRight?: IconAsset;
- /** Component to be displayed on the right */
- rightComponent?: ReactNode;
+ /** Should render component on the right */
+ shouldShowRightComponent?: boolean;
- /** A description text to show under the title */
- description?: string;
+ /** Component to be displayed on the right */
+ rightComponent?: ReactNode;
- /** Should the description be shown above the title (instead of the other way around) */
- shouldShowDescriptionOnTop?: boolean;
+ /** A description text to show under the title */
+ description?: string;
- /** Error to display below the title */
- error?: string;
+ /** Should the description be shown above the title (instead of the other way around) */
+ shouldShowDescriptionOnTop?: boolean;
- /** Error to display at the bottom of the component */
- errorText?: string;
+ /** Error to display below the title */
+ error?: string;
- /** A boolean flag that gives the icon a green fill if true */
- success?: boolean;
+ /** Error to display at the bottom of the component */
+ errorText?: string;
- /** Whether item is focused or active */
- focused?: boolean;
+ /** A boolean flag that gives the icon a green fill if true */
+ success?: boolean;
- /** Should we disable this menu item? */
- disabled?: boolean;
+ /** Whether item is focused or active */
+ focused?: boolean;
- /** Text that appears above the title */
- label?: string;
+ /** Should we disable this menu item? */
+ disabled?: boolean;
- /** Label to be displayed on the right */
- rightLabel?: string;
+ /** Text that appears above the title */
+ label?: string;
- /** Text to display for the item */
- title?: string;
+ /** Label to be displayed on the right */
+ rightLabel?: string;
- /** A right-aligned subtitle for this menu option */
- subtitle?: string | number;
+ /** Text to display for the item */
+ title?: string;
- /** Should the title show with normal font weight (not bold) */
- shouldShowBasicTitle?: boolean;
+ /** A right-aligned subtitle for this menu option */
+ subtitle?: string | number;
- /** Should we make this selectable with a checkbox */
- shouldShowSelectedState?: boolean;
+ /** Should the title show with normal font weight (not bold) */
+ shouldShowBasicTitle?: boolean;
- /** Whether this item is selected */
- isSelected?: boolean;
+ /** Should we make this selectable with a checkbox */
+ shouldShowSelectedState?: boolean;
- /** Prop to identify if we should load avatars vertically instead of diagonally */
- shouldStackHorizontally?: boolean;
+ /** Whether this item is selected */
+ isSelected?: boolean;
- /** Prop to represent the size of the avatar images to be shown */
- avatarSize?: (typeof CONST.AVATAR_SIZE)[keyof typeof CONST.AVATAR_SIZE];
+ /** Prop to identify if we should load avatars vertically instead of diagonally */
+ shouldStackHorizontally?: boolean;
- /** Avatars to show on the right of the menu item */
- floatRightAvatars?: IconType[];
+ /** Prop to represent the size of the avatar images to be shown */
+ avatarSize?: (typeof CONST.AVATAR_SIZE)[keyof typeof CONST.AVATAR_SIZE];
- /** Prop to represent the size of the float right avatar images to be shown */
- floatRightAvatarSize?: ValueOf;
+ /** Avatars to show on the right of the menu item */
+ floatRightAvatars?: IconType[];
- /** Affects avatar size */
- viewMode?: ValueOf;
+ /** Prop to represent the size of the float right avatar images to be shown */
+ floatRightAvatarSize?: ValueOf;
- /** Used to truncate the text with an ellipsis after computing the text layout */
- numberOfLinesTitle?: number;
+ /** Affects avatar size */
+ viewMode?: ValueOf;
- /** Whether we should use small avatar subscript sizing the for menu item */
- isSmallAvatarSubscriptMenu?: boolean;
+ /** Used to truncate the text with an ellipsis after computing the text layout */
+ numberOfLinesTitle?: number;
- /** The type of brick road indicator to show. */
- brickRoadIndicator?: ValueOf;
+ /** Whether we should use small avatar subscript sizing the for menu item */
+ isSmallAvatarSubscriptMenu?: boolean;
- /** Should render the content in HTML format */
- shouldRenderAsHTML?: boolean;
+ /** The type of brick road indicator to show. */
+ brickRoadIndicator?: ValueOf;
- /** Should we grey out the menu item when it is disabled? */
- shouldGreyOutWhenDisabled?: boolean;
+ /** Should render the content in HTML format */
+ shouldRenderAsHTML?: boolean;
- /** The action accept for anonymous user or not */
- isAnonymousAction?: boolean;
+ /** Should we grey out the menu item when it is disabled? */
+ shouldGreyOutWhenDisabled?: boolean;
- /** Flag to indicate whether or not text selection should be disabled from long-pressing the menu item. */
- shouldBlockSelection?: boolean;
+ /** The action accept for anonymous user or not */
+ isAnonymousAction?: boolean;
- /** Whether should render title as HTML or as Text */
- shouldParseTitle?: false;
+ /** Flag to indicate whether or not text selection should be disabled from long-pressing the menu item. */
+ shouldBlockSelection?: boolean;
- /** Should check anonymous user in onPress function */
- shouldCheckActionAllowedOnPress?: boolean;
+ /** Whether should render title as HTML or as Text */
+ shouldParseTitle?: false;
- /** Text to display under the main item */
- furtherDetails?: string;
+ /** Should check anonymous user in onPress function */
+ shouldCheckActionAllowedOnPress?: boolean;
- /** The function that should be called when this component is LongPressed or right-clicked. */
- onSecondaryInteraction?: () => void;
+ /** Text to display under the main item */
+ furtherDetails?: string;
- /** Array of objects that map display names to their corresponding tooltip */
- titleWithTooltips?: DisplayNameWithTooltip[];
+ /** The function that should be called when this component is LongPressed or right-clicked. */
+ onSecondaryInteraction?: (event: GestureResponderEvent | MouseEvent) => void;
- /** Icon should be displayed in its own color */
- displayInDefaultIconColor?: boolean;
+ /** Array of objects that map display names to their corresponding tooltip */
+ titleWithTooltips?: DisplayNameWithTooltip[];
- /** Determines how the icon should be resized to fit its container */
- contentFit?: ImageContentFit;
- };
+ /** Icon should be displayed in its own color */
+ displayInDefaultIconColor?: boolean;
+
+ /** Determines how the icon should be resized to fit its container */
+ contentFit?: ImageContentFit;
+};
function MenuItem(
{
@@ -300,7 +291,7 @@ function MenuItem(
const theme = useTheme();
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
- const combinedStyle = StyleUtils.combineStyles(style ?? {}, styles.popoverMenuItem);
+ const combinedStyle = [style, styles.popoverMenuItem];
const {isSmallScreenWidth} = useWindowDimensions();
const [html, setHtml] = useState('');
const titleRef = useRef('');
@@ -525,17 +516,18 @@ function MenuItem(
{error}
)}
- {furtherDetailsIcon && !!furtherDetails && (
+ {!!furtherDetails && (
-
+ {!!furtherDetailsIcon && (
+
+ )}
{furtherDetails}
diff --git a/src/components/MenuItemList.js b/src/components/MenuItemList.js
deleted file mode 100644
index c9eee8e888e1..000000000000
--- a/src/components/MenuItemList.js
+++ /dev/null
@@ -1,62 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import _ from 'underscore';
-import useSingleExecution from '@hooks/useSingleExecution';
-import * as ReportActionContextMenu from '@pages/home/report/ContextMenu/ReportActionContextMenu';
-import CONST from '@src/CONST';
-import MenuItem from './MenuItem';
-import menuItemPropTypes from './menuItemPropTypes';
-
-const propTypes = {
- /** An array of props that are pass to individual MenuItem components */
- menuItems: PropTypes.arrayOf(PropTypes.shape(menuItemPropTypes)),
-
- /** Whether or not to use the single execution hook */
- shouldUseSingleExecution: PropTypes.bool,
-};
-const defaultProps = {
- menuItems: [],
- shouldUseSingleExecution: false,
-};
-
-function MenuItemList(props) {
- let popoverAnchor;
- const {isExecuting, singleExecution} = useSingleExecution();
-
- /**
- * Handle the secondary interaction for a menu item.
- *
- * @param {*} link the menu item link or function to get the link
- * @param {Event} e the interaction event
- */
- const secondaryInteraction = (link, e) => {
- if (typeof link === 'function') {
- link().then((url) => ReportActionContextMenu.showContextMenu(CONST.CONTEXT_MENU_TYPES.LINK, e, url, popoverAnchor));
- } else if (!_.isEmpty(link)) {
- ReportActionContextMenu.showContextMenu(CONST.CONTEXT_MENU_TYPES.LINK, e, link, popoverAnchor);
- }
- };
-
- return (
- <>
- {_.map(props.menuItems, (menuItemProps) => (
-
+ setIsConfirmModalVisible(false)}
+ prompt={translate('iou.cancelPaymentConfirmation')}
+ confirmText={translate('iou.cancelPayment')}
+ cancelText={translate('common.dismiss')}
+ danger
+ />
);
}
diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js
index 13dce9337673..f66e73a2ef02 100755
--- a/src/components/MoneyRequestConfirmationList.js
+++ b/src/components/MoneyRequestConfirmationList.js
@@ -657,7 +657,7 @@ function MoneyRequestConfirmationList(props) {
/>
{!shouldShowAllFields && (
)}
diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js
index 488630dd0590..be42abc797dd 100644
--- a/src/components/MoneyRequestHeader.js
+++ b/src/components/MoneyRequestHeader.js
@@ -100,7 +100,16 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction,
threeDotsMenuItems.push({
icon: Expensicons.Receipt,
text: translate('receipt.addReceipt'),
- onSelected: () => Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT)),
+ onSelected: () =>
+ Navigation.navigate(
+ ROUTES.MONEY_REQUEST_STEP_SCAN.getRoute(
+ CONST.IOU.ACTION.EDIT,
+ CONST.IOU.TYPE.REQUEST,
+ transaction.transactionID,
+ report.reportID,
+ Navigation.getActiveRouteWithoutParams(),
+ ),
+ ),
});
}
threeDotsMenuItems.push({
diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js
index 7ec95aec951f..36d424ea28f2 100755
--- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js
+++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js
@@ -277,7 +277,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({
const shouldShowTags = isPolicyExpenseChat && OptionsListUtils.hasEnabledOptions(_.values(policyTagList));
// A flag for showing tax rate
- const shouldShowTax = isPolicyExpenseChat && policy.isTaxTrackingEnabled;
+ const shouldShowTax = isPolicyExpenseChat && policy && policy.isTaxTrackingEnabled;
// A flag for showing the billable field
const shouldShowBillable = !lodashGet(policy, 'disabledFields.defaultBillable', true);
@@ -726,26 +726,6 @@ function MoneyTemporaryForRefactorRequestConfirmationList({
)}
{shouldShowAllFields && (
<>
- {shouldShowDate && (
- {
- if (isEditingSplitBill) {
- Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(reportID, reportActionID, CONST.EDIT_REQUEST_FIELD.DATE));
- return;
- }
- Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DATE.getRoute(iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams()));
- }}
- disabled={didConfirm}
- interactive={!isReadOnly}
- brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isCreatedMissing(transaction) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''}
- error={shouldDisplayFieldError && TransactionUtils.isCreatedMissing(transaction) ? translate('common.error.enterDate') : ''}
- />
- )}
{isDistanceRequest && (
)}
+ {shouldShowDate && (
+ {
+ if (isEditingSplitBill) {
+ Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(reportID, reportActionID, CONST.EDIT_REQUEST_FIELD.DATE));
+ return;
+ }
+ Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DATE.getRoute(iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams()));
+ }}
+ disabled={didConfirm}
+ interactive={!isReadOnly}
+ brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isCreatedMissing(transaction) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''}
+ error={shouldDisplayFieldError && TransactionUtils.isCreatedMissing(transaction) ? translate('common.error.enterDate') : ''}
+ />
+ )}
{shouldShowCategories && (
{
+ if (pinchEnabled) {
+ return;
+ }
+ setPinchEnabled(true);
+ }, [pinchEnabled]);
+
const pinchGesture = Gesture.Pinch()
+ .enabled(pinchEnabled)
.onTouchesDown((evt, state) => {
// we don't want to activate pinch gesture when we are scrolling pager
if (!isScrolling.value) {
@@ -466,6 +476,11 @@ function MultiGestureCanvas({canvasSize, isActive = true, onScaleChanged, childr
origin.y.value = adjustFocal.y;
})
.onChange((evt) => {
+ if (evt.numberOfPointers !== 2) {
+ runOnJS(setPinchEnabled)(false);
+ return;
+ }
+
const newZoomScale = pinchScaleOffset.value * evt.scale;
if (zoomScale.value >= zoomRange.min * zoomScaleBounceFactors.min && zoomScale.value <= zoomRange.max * zoomScaleBounceFactors.max) {
diff --git a/src/components/OfflineWithFeedback.tsx b/src/components/OfflineWithFeedback.tsx
index fa0ae5162346..c7d038888c39 100644
--- a/src/components/OfflineWithFeedback.tsx
+++ b/src/components/OfflineWithFeedback.tsx
@@ -4,6 +4,7 @@ import {View} from 'react-native';
import useNetwork from '@hooks/useNetwork';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
+import mapChildrenFlat from '@libs/mapChildrenFlat';
import shouldRenderOffscreen from '@libs/shouldRenderOffscreen';
import CONST from '@src/CONST';
import type * as OnyxCommon from '@src/types/onyx/OnyxCommon';
@@ -97,8 +98,8 @@ function OfflineWithFeedback({
* This method applies the strikethrough to all the children passed recursively
*/
const applyStrikeThrough = useCallback(
- (childrenProp: React.ReactNode): React.ReactNode =>
- React.Children.map(childrenProp, (child) => {
+ (childrenProp: React.ReactNode): React.ReactNode => {
+ const strikedThroughChildren = mapChildrenFlat(childrenProp, (child) => {
if (!React.isValidElement(child)) {
return child;
}
@@ -112,7 +113,10 @@ function OfflineWithFeedback({
}
return React.cloneElement(child, props);
- }),
+ });
+
+ return strikedThroughChildren;
+ },
[StyleUtils, styles],
);
diff --git a/src/components/Onfido/BaseOnfidoWeb.js b/src/components/Onfido/BaseOnfidoWeb.js
index 09ec96cf5b1e..ee206b15fc24 100644
--- a/src/components/Onfido/BaseOnfidoWeb.js
+++ b/src/components/Onfido/BaseOnfidoWeb.js
@@ -5,8 +5,7 @@ import _ from 'underscore';
import useLocalize from '@hooks/useLocalize';
import useTheme from '@hooks/useTheme';
import Log from '@libs/Log';
-import fontFamily from '@styles/utils/fontFamily';
-import fontWeightBold from '@styles/utils/fontWeight/bold';
+import FontUtils from '@styles/utils/FontUtils';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import './index.css';
@@ -18,11 +17,11 @@ function initializeOnfido({sdkToken, onSuccess, onError, onUserExit, preferredLo
containerId: CONST.ONFIDO.CONTAINER_ID,
useMemoryHistory: true,
customUI: {
- fontFamilyTitle: `${fontFamily.EXP_NEUE}, -apple-system, serif`,
- fontFamilySubtitle: `${fontFamily.EXP_NEUE}, -apple-system, serif`,
- fontFamilyBody: `${fontFamily.EXP_NEUE}, -apple-system, serif`,
+ fontFamilyTitle: `${FontUtils.fontFamily.platform.EXP_NEUE}, -apple-system, serif`,
+ fontFamilySubtitle: `${FontUtils.fontFamily.platform.EXP_NEUE}, -apple-system, serif`,
+ fontFamilyBody: `${FontUtils.fontFamily.platform.EXP_NEUE}, -apple-system, serif`,
fontSizeTitle: `${variables.fontSizeLarge}px`,
- fontWeightTitle: fontWeightBold,
+ fontWeightTitle: FontUtils.fontWeight.bold,
fontWeightSubtitle: 400,
fontSizeSubtitle: `${variables.fontSizeNormal}px`,
colorContentTitle: theme.text,
diff --git a/src/components/OptionRow.tsx b/src/components/OptionRow.tsx
index 79b72b378e46..dd8cd115e13f 100644
--- a/src/components/OptionRow.tsx
+++ b/src/components/OptionRow.tsx
@@ -268,8 +268,8 @@ function OptionRow({
onSelectedStatePressed(option)}
disabled={isDisabled}
- role={CONST.ROLE.CHECKBOX}
- accessibilityLabel={CONST.ROLE.CHECKBOX}
+ role={CONST.ROLE.BUTTON}
+ accessibilityLabel={CONST.ROLE.BUTTON}
>
diff --git a/src/components/OptionsSelector/BaseOptionsSelector.js b/src/components/OptionsSelector/BaseOptionsSelector.js
index 792073b72613..197829bb1ea9 100755
--- a/src/components/OptionsSelector/BaseOptionsSelector.js
+++ b/src/components/OptionsSelector/BaseOptionsSelector.js
@@ -80,8 +80,12 @@ class BaseOptionsSelector extends Component {
this.incrementPage = this.incrementPage.bind(this);
this.sliceSections = this.sliceSections.bind(this);
this.calculateAllVisibleOptionsCount = this.calculateAllVisibleOptionsCount.bind(this);
+ this.handleFocusIn = this.handleFocusIn.bind(this);
+ this.handleFocusOut = this.handleFocusOut.bind(this);
this.debouncedUpdateSearchValue = _.debounce(this.updateSearchValue, CONST.TIMING.SEARCH_OPTION_LIST_DEBOUNCE_TIME);
this.relatedTarget = null;
+ this.accessibilityRoles = _.values(CONST.ROLE);
+ this.isWebOrDesktop = [CONST.PLATFORM.DESKTOP, CONST.PLATFORM.WEB].includes(getPlatform());
const allOptions = this.flattenSections();
const sections = this.sliceSections();
@@ -95,12 +99,15 @@ class BaseOptionsSelector extends Component {
shouldShowReferralModal: false,
errorMessage: '',
paginationPage: 1,
+ disableEnterShortCut: false,
value: '',
};
}
componentDidMount() {
- this.subscribeToKeyboardShortcut();
+ this.subscribeToEnterShortcut();
+ this.subscribeToCtrlEnterShortcut();
+ this.subscribeActiveElement();
if (this.props.isFocused && this.props.autoFocus && this.textInput) {
this.focusTimeout = setTimeout(() => {
@@ -112,9 +119,18 @@ class BaseOptionsSelector extends Component {
}
componentDidUpdate(prevProps, prevState) {
+ if (prevState.disableEnterShortCut !== this.state.disableEnterShortCut) {
+ if (this.state.disableEnterShortCut) {
+ this.unsubscribeEnter();
+ } else {
+ this.subscribeToEnterShortcut();
+ }
+ }
+
if (prevProps.isFocused !== this.props.isFocused) {
if (this.props.isFocused) {
- this.subscribeToKeyboardShortcut();
+ this.subscribeToEnterShortcut();
+ this.subscribeToCtrlEnterShortcut();
} else {
this.unSubscribeFromKeyboardShortcut();
}
@@ -123,7 +139,7 @@ class BaseOptionsSelector extends Component {
// Screen coming back into focus, for example
// when doing Cmd+Shift+K, then Cmd+K, then Cmd+Shift+K.
// Only applies to platforms that support keyboard shortcuts
- if ([CONST.PLATFORM.DESKTOP, CONST.PLATFORM.WEB].includes(getPlatform()) && !prevProps.isFocused && this.props.isFocused && this.props.autoFocus && this.textInput) {
+ if (this.isWebOrDesktop && !prevProps.isFocused && this.props.isFocused && this.props.autoFocus && this.textInput) {
setTimeout(() => {
this.textInput.focus();
}, CONST.ANIMATED_TRANSITION);
@@ -259,7 +275,36 @@ class BaseOptionsSelector extends Component {
this.setState((prevState) => ({shouldShowReferralModal: !prevState.shouldShowReferralModal}));
}
- subscribeToKeyboardShortcut() {
+ handleFocusIn() {
+ const activeElement = document.activeElement;
+ this.setState({
+ disableEnterShortCut: activeElement && this.accessibilityRoles.includes(activeElement.role) && activeElement.role !== CONST.ROLE.PRESENTATION,
+ });
+ }
+
+ handleFocusOut() {
+ this.setState({
+ disableEnterShortCut: false,
+ });
+ }
+
+ subscribeActiveElement() {
+ if (!this.isWebOrDesktop) {
+ return;
+ }
+ document.addEventListener('focusin', this.handleFocusIn);
+ document.addEventListener('focusout', this.handleFocusOut);
+ }
+
+ unSubscribeActiveElement() {
+ if (!this.isWebOrDesktop) {
+ return;
+ }
+ document.removeEventListener('focusin', this.handleFocusIn);
+ document.removeEventListener('focusout', this.handleFocusOut);
+ }
+
+ subscribeToEnterShortcut() {
const enterConfig = CONST.KEYBOARD_SHORTCUTS.ENTER;
this.unsubscribeEnter = KeyboardShortcut.subscribe(
enterConfig.shortcutKey,
@@ -269,7 +314,9 @@ class BaseOptionsSelector extends Component {
true,
() => !this.state.allOptions[this.state.focusedIndex],
);
+ }
+ subscribeToCtrlEnterShortcut() {
const CTRLEnterConfig = CONST.KEYBOARD_SHORTCUTS.CTRL_ENTER;
this.unsubscribeCTRLEnter = KeyboardShortcut.subscribe(
CTRLEnterConfig.shortcutKey,
diff --git a/src/components/PopoverMenu.tsx b/src/components/PopoverMenu.tsx
index 502bdbf83b53..2d6f74f7cd46 100644
--- a/src/components/PopoverMenu.tsx
+++ b/src/components/PopoverMenu.tsx
@@ -127,6 +127,14 @@ function PopoverMenu({
{isActive: isVisible},
);
+ const onModalHide = () => {
+ setFocusedIndex(-1);
+ if (selectedItemIndex.current !== null) {
+ menuItems[selectedItemIndex.current].onSelected();
+ selectedItemIndex.current = null;
+ }
+ };
+
return (
{
- setFocusedIndex(-1);
- if (selectedItemIndex.current !== null) {
- menuItems[selectedItemIndex.current].onSelected();
- selectedItemIndex.current = null;
- }
- }}
+ onModalHide={onModalHide}
animationIn={animationIn}
animationOut={animationOut}
animationInTiming={animationInTiming}
diff --git a/src/components/PopoverWithMeasuredContent.tsx b/src/components/PopoverWithMeasuredContent.tsx
index b636f90cd7ca..792002441ac6 100644
--- a/src/components/PopoverWithMeasuredContent.tsx
+++ b/src/components/PopoverWithMeasuredContent.tsx
@@ -36,6 +36,12 @@ function PopoverWithMeasuredContent({
},
children,
withoutOverlay = false,
+ fullscreen = true,
+ shouldCloseOnOutsideClick = false,
+ shouldSetModalVisibility = true,
+ statusBarTranslucent = true,
+ avoidKeyboard = false,
+ hideModalContentWhileAnimating = false,
...props
}: PopoverWithMeasuredContentProps) {
const styles = useThemeStyles();
@@ -115,6 +121,12 @@ function PopoverWithMeasuredContent({
anchorAlignment={anchorAlignment}
isVisible={isVisible}
withoutOverlay={withoutOverlay}
+ fullscreen={fullscreen}
+ shouldCloseOnOutsideClick={shouldCloseOnOutsideClick}
+ shouldSetModalVisibility={shouldSetModalVisibility}
+ statusBarTranslucent={statusBarTranslucent}
+ avoidKeyboard={avoidKeyboard}
+ hideModalContentWhileAnimating={hideModalContentWhileAnimating}
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
anchorPosition={shiftedAnchorPosition}
diff --git a/src/components/ProcessMoneyRequestHoldMenu.tsx b/src/components/ProcessMoneyRequestHoldMenu.tsx
new file mode 100644
index 000000000000..1b711633ed3b
--- /dev/null
+++ b/src/components/ProcessMoneyRequestHoldMenu.tsx
@@ -0,0 +1,66 @@
+import React from 'react';
+import {View} from 'react-native';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import Button from './Button';
+import HoldMenuSectionList from './HoldMenuSectionList';
+import type {PopoverAnchorPosition} from './Modal/types';
+import Popover from './Popover';
+import type {AnchorAlignment} from './Popover/types';
+import Text from './Text';
+import TextPill from './TextPill';
+
+type ProcessMoneyRequestHoldMenuProps = {
+ /** Whether the content is visible */
+ isVisible: boolean;
+
+ /** Method to trigger when pressing outside of the popover menu to close it */
+ onClose: () => void;
+
+ /** Method to trigger when pressing confirm button */
+ onConfirm: () => void;
+
+ /** The anchor position of the popover menu */
+ anchorPosition?: PopoverAnchorPosition;
+
+ /** The anchor alignment of the popover menu */
+ anchorAlignment: AnchorAlignment;
+
+ /** The anchor ref of the popover menu */
+ anchorRef: React.RefObject;
+};
+
+function ProcessMoneyRequestHoldMenu({isVisible, onClose, onConfirm, anchorPosition, anchorAlignment, anchorRef}: ProcessMoneyRequestHoldMenuProps) {
+ const {translate} = useLocalize();
+ const styles = useThemeStyles();
+
+ return (
+
+
+
+ {translate('iou.holdEducationalTitle')}
+ {translate('iou.hold')};
+
+
+
+
+
+ );
+}
+
+ProcessMoneyRequestHoldMenu.displayName = 'ProcessMoneyRequestHoldMenu';
+
+export default ProcessMoneyRequestHoldMenu;
diff --git a/src/components/QRCode.tsx b/src/components/QRCode.tsx
index 89c367bab222..3accb19acfaf 100644
--- a/src/components/QRCode.tsx
+++ b/src/components/QRCode.tsx
@@ -1,13 +1,13 @@
-import type {Ref} from 'react';
import React from 'react';
import type {ImageSourcePropType} from 'react-native';
import QRCodeLibrary from 'react-native-qrcode-svg';
+import type {Svg} from 'react-native-svg';
import useTheme from '@hooks/useTheme';
import CONST from '@src/CONST';
-type LogoRatio = typeof CONST.QR.DEFAULT_LOGO_SIZE_RATIO | typeof CONST.QR.EXPENSIFY_LOGO_SIZE_RATIO;
+type QRCodeLogoRatio = typeof CONST.QR.DEFAULT_LOGO_SIZE_RATIO | typeof CONST.QR.EXPENSIFY_LOGO_SIZE_RATIO;
-type LogoMarginRatio = typeof CONST.QR.DEFAULT_LOGO_MARGIN_RATIO | typeof CONST.QR.EXPENSIFY_LOGO_MARGIN_RATIO;
+type QRCodeLogoMarginRatio = typeof CONST.QR.DEFAULT_LOGO_MARGIN_RATIO | typeof CONST.QR.EXPENSIFY_LOGO_MARGIN_RATIO;
type QRCodeProps = {
/** The QR code URL */
@@ -20,10 +20,10 @@ type QRCodeProps = {
logo?: ImageSourcePropType;
/** The size ratio of logo to QR code */
- logoRatio?: LogoRatio;
+ logoRatio?: QRCodeLogoRatio;
/** The size ratio of margin around logo to QR code */
- logoMarginRatio?: LogoMarginRatio;
+ logoMarginRatio?: QRCodeLogoMarginRatio;
/** The QRCode size */
size?: number;
@@ -38,7 +38,7 @@ type QRCodeProps = {
* Function to retrieve the internal component ref and be able to call it's
* methods
*/
- getRef?: (ref: Ref) => Ref;
+ getRef?: (ref: Svg) => Svg;
};
function QRCode({url, logo, getRef, size = 120, color, backgroundColor, logoRatio = CONST.QR.DEFAULT_LOGO_SIZE_RATIO, logoMarginRatio = CONST.QR.DEFAULT_LOGO_MARGIN_RATIO}: QRCodeProps) {
@@ -62,3 +62,4 @@ function QRCode({url, logo, getRef, size = 120, color, backgroundColor, logoRati
QRCode.displayName = 'QRCode';
export default QRCode;
+export type {QRCodeLogoMarginRatio, QRCodeLogoRatio};
diff --git a/src/components/QRShare/QRShareWithDownload/index.native.js b/src/components/QRShare/QRShareWithDownload/index.native.js
deleted file mode 100644
index e64c7b69df4a..000000000000
--- a/src/components/QRShare/QRShareWithDownload/index.native.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import React, {forwardRef, useImperativeHandle, useRef} from 'react';
-import ViewShot from 'react-native-view-shot';
-import getQrCodeFileName from '@components/QRShare/getQrCodeDownloadFileName';
-import {qrShareDefaultProps, qrSharePropTypes} from '@components/QRShare/propTypes';
-import useNetwork from '@hooks/useNetwork';
-import fileDownload from '@libs/fileDownload';
-import QRShare from '..';
-
-function QRShareWithDownload({innerRef, ...props}) {
- const {isOffline} = useNetwork();
- const qrCodeScreenshotRef = useRef(null);
-
- useImperativeHandle(
- innerRef,
- () => ({
- download: () => qrCodeScreenshotRef.current.capture().then((uri) => fileDownload(uri, getQrCodeFileName(props.title))),
- }),
- [props.title],
- );
-
- return (
-
-
-
- );
-}
-
-QRShareWithDownload.propTypes = qrSharePropTypes;
-QRShareWithDownload.defaultProps = qrShareDefaultProps;
-QRShareWithDownload.displayName = 'QRShareWithDownload';
-
-const QRShareWithDownloadWithRef = forwardRef((props, ref) => (
-
-));
-
-QRShareWithDownloadWithRef.displayName = 'QRShareWithDownloadWithRef';
-
-export default QRShareWithDownloadWithRef;
diff --git a/src/components/QRShare/QRShareWithDownload/index.native.tsx b/src/components/QRShare/QRShareWithDownload/index.native.tsx
new file mode 100644
index 000000000000..d1d9f13147f1
--- /dev/null
+++ b/src/components/QRShare/QRShareWithDownload/index.native.tsx
@@ -0,0 +1,36 @@
+import type {ForwardedRef} from 'react';
+import React, {forwardRef, useImperativeHandle, useRef} from 'react';
+import ViewShot from 'react-native-view-shot';
+import getQrCodeFileName from '@components/QRShare/getQrCodeDownloadFileName';
+import type {QRShareProps} from '@components/QRShare/types';
+import useNetwork from '@hooks/useNetwork';
+import fileDownload from '@libs/fileDownload';
+import QRShare from '..';
+import type QRShareWithDownloadHandle from './types';
+
+function QRShareWithDownload(props: QRShareProps, ref: ForwardedRef) {
+ const {isOffline} = useNetwork();
+ const qrCodeScreenshotRef = useRef(null);
+
+ useImperativeHandle(
+ ref,
+ () => ({
+ download: () => qrCodeScreenshotRef.current?.capture?.().then((uri) => fileDownload(uri, getQrCodeFileName(props.title))),
+ }),
+ [props.title],
+ );
+
+ return (
+
+
+
+ );
+}
+
+QRShareWithDownload.displayName = 'QRShareWithDownload';
+
+export default forwardRef(QRShareWithDownload);
diff --git a/src/components/QRShare/QRShareWithDownload/index.js b/src/components/QRShare/QRShareWithDownload/index.tsx
similarity index 59%
rename from src/components/QRShare/QRShareWithDownload/index.js
rename to src/components/QRShare/QRShareWithDownload/index.tsx
index bf18a8eedaa4..4a327e9c9249 100644
--- a/src/components/QRShare/QRShareWithDownload/index.js
+++ b/src/components/QRShare/QRShareWithDownload/index.tsx
@@ -1,22 +1,24 @@
+import type {ForwardedRef} from 'react';
import React, {forwardRef, useImperativeHandle, useRef} from 'react';
import getQrCodeFileName from '@components/QRShare/getQrCodeDownloadFileName';
-import {qrShareDefaultProps, qrSharePropTypes} from '@components/QRShare/propTypes';
+import type {QRShareHandle, QRShareProps} from '@components/QRShare/types';
import useNetwork from '@hooks/useNetwork';
import fileDownload from '@libs/fileDownload';
import QRShare from '..';
+import type QRShareWithDownloadHandle from './types';
-function QRShareWithDownload({innerRef, ...props}) {
+function QRShareWithDownload(props: QRShareProps, ref: ForwardedRef) {
const {isOffline} = useNetwork();
- const qrShareRef = useRef(null);
+ const qrShareRef = useRef(null);
useImperativeHandle(
- innerRef,
+ ref,
() => ({
download: () =>
new Promise((resolve, reject) => {
// eslint-disable-next-line es/no-optional-chaining
const svg = qrShareRef.current?.getSvg();
- if (svg == null) {
+ if (!svg) {
return reject();
}
@@ -31,23 +33,11 @@ function QRShareWithDownload({innerRef, ...props}) {
ref={qrShareRef}
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
- logo={isOffline ? null : props.logo}
+ logo={isOffline ? undefined : props.logo}
/>
);
}
-QRShareWithDownload.propTypes = qrSharePropTypes;
-QRShareWithDownload.defaultProps = qrShareDefaultProps;
QRShareWithDownload.displayName = 'QRShareWithDownload';
-const QRShareWithDownloadWithRef = forwardRef((props, ref) => (
-
-));
-
-QRShareWithDownloadWithRef.displayName = 'QRShareWithDownloadWithRef';
-
-export default QRShareWithDownloadWithRef;
+export default forwardRef(QRShareWithDownload);
diff --git a/src/components/QRShare/QRShareWithDownload/types.ts b/src/components/QRShare/QRShareWithDownload/types.ts
new file mode 100644
index 000000000000..c5df9cba55e2
--- /dev/null
+++ b/src/components/QRShare/QRShareWithDownload/types.ts
@@ -0,0 +1,5 @@
+type QRShareWithDownloadHandle = {
+ download: () => Promise | undefined;
+};
+
+export default QRShareWithDownloadHandle;
diff --git a/src/components/QRShare/getQrCodeDownloadFileName.js b/src/components/QRShare/getQrCodeDownloadFileName.js
deleted file mode 100644
index c1e73a1794fb..000000000000
--- a/src/components/QRShare/getQrCodeDownloadFileName.js
+++ /dev/null
@@ -1,3 +0,0 @@
-const getQrCodeDownloadFileName = (title) => `${title}-ShareCode.png`;
-
-export default getQrCodeDownloadFileName;
diff --git a/src/components/QRShare/getQrCodeDownloadFileName.ts b/src/components/QRShare/getQrCodeDownloadFileName.ts
new file mode 100644
index 000000000000..7041eac2b4b4
--- /dev/null
+++ b/src/components/QRShare/getQrCodeDownloadFileName.ts
@@ -0,0 +1,3 @@
+const getQrCodeDownloadFileName = (title: string): string => `${title}-ShareCode.png`;
+
+export default getQrCodeDownloadFileName;
diff --git a/src/components/QRShare/index.js b/src/components/QRShare/index.tsx
similarity index 76%
rename from src/components/QRShare/index.js
rename to src/components/QRShare/index.tsx
index b1fc4c6fa2d8..c7e9e7637a6c 100644
--- a/src/components/QRShare/index.js
+++ b/src/components/QRShare/index.tsx
@@ -1,6 +1,8 @@
+import type {ForwardedRef} from 'react';
import React, {forwardRef, useImperativeHandle, useRef, useState} from 'react';
+import type {LayoutChangeEvent} from 'react-native';
import {View} from 'react-native';
-import _ from 'underscore';
+import type {Svg} from 'react-native-svg';
import ExpensifyWordmark from '@assets/images/expensify-wordmark.svg';
import ImageSVG from '@components/ImageSVG';
import QRCode from '@components/QRCode';
@@ -8,24 +10,24 @@ import Text from '@components/Text';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import variables from '@styles/variables';
-import {qrShareDefaultProps, qrSharePropTypes} from './propTypes';
+import type {QRShareHandle, QRShareProps} from './types';
-function QRShare({innerRef, url, title, subtitle, logo, logoRatio, logoMarginRatio}) {
+function QRShare({url, title, subtitle, logo, logoRatio, logoMarginRatio}: QRShareProps, ref: ForwardedRef) {
const styles = useThemeStyles();
const theme = useTheme();
const [qrCodeSize, setQrCodeSize] = useState(1);
- const svgRef = useRef(null);
+ const svgRef = useRef
- {!_.isEmpty(subtitle) && (
+ {!!subtitle && (
(
-
-));
-
-QRShareWithRef.displayName = 'QRShareWithRef';
-
-export default QRShareWithRef;
+export default forwardRef(QRShare);
diff --git a/src/components/QRShare/propTypes.js b/src/components/QRShare/propTypes.js
deleted file mode 100644
index 28275bc724b1..000000000000
--- a/src/components/QRShare/propTypes.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import PropTypes from 'prop-types';
-
-const qrSharePropTypes = {
- /**
- * The QR code URL
- */
- url: PropTypes.string.isRequired,
-
- /**
- * The title that is displayed below the QR Code (usually the user or report name)
- */
- title: PropTypes.string.isRequired,
-
- /**
- * The subtitle which will be shown below the title (usually user email or workspace name)
- * */
- subtitle: PropTypes.string,
-
- /**
- * The logo which will be display in the middle of the QR code
- */
- logo: PropTypes.oneOfType([PropTypes.shape({uri: PropTypes.string}), PropTypes.number, PropTypes.string]),
-
- /**
- * The size ratio of logo to QR code
- */
- logoRatio: PropTypes.number,
-
- /**
- * The size ratio of margin around logo to QR code
- */
- logoMarginRatio: PropTypes.number,
-
- /**
- * Forwarded ref
- */
- innerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
-};
-
-const qrShareDefaultProps = {
- subtitle: undefined,
- logo: undefined,
-};
-
-export {qrSharePropTypes, qrShareDefaultProps};
diff --git a/src/components/QRShare/types.ts b/src/components/QRShare/types.ts
new file mode 100644
index 000000000000..db9afdf73c2a
--- /dev/null
+++ b/src/components/QRShare/types.ts
@@ -0,0 +1,41 @@
+import type {ImageSourcePropType} from 'react-native';
+import type {Svg} from 'react-native-svg';
+import type {QRCodeLogoMarginRatio, QRCodeLogoRatio} from '@components/QRCode';
+
+type QRShareProps = {
+ /**
+ * The QR code URL
+ */
+ url: string;
+
+ /**
+ * The title that is displayed below the QR Code (usually the user or report name)
+ */
+ title: string;
+
+ /**
+ * The subtitle which will be shown below the title (usually user email or workspace name)
+ * */
+ subtitle?: string;
+
+ /**
+ * The logo which will be display in the middle of the QR code
+ */
+ logo?: ImageSourcePropType;
+
+ /**
+ * The size ratio of logo to QR code
+ */
+ logoRatio?: QRCodeLogoRatio;
+
+ /**
+ * The size ratio of margin around logo to QR code
+ */
+ logoMarginRatio?: QRCodeLogoMarginRatio;
+};
+
+type QRShareHandle = {
+ getSvg: () => Svg | undefined;
+};
+
+export type {QRShareHandle, QRShareProps};
diff --git a/src/components/Reactions/AddReactionBubble.js b/src/components/Reactions/AddReactionBubble.tsx
similarity index 62%
rename from src/components/Reactions/AddReactionBubble.js
rename to src/components/Reactions/AddReactionBubble.tsx
index a9bfdd367615..52751368a0ae 100644
--- a/src/components/Reactions/AddReactionBubble.js
+++ b/src/components/Reactions/AddReactionBubble.tsx
@@ -1,81 +1,75 @@
-import PropTypes from 'prop-types';
import React, {useEffect, useRef} from 'react';
import {View} from 'react-native';
+import type {Emoji} from '@assets/emojis/types';
import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';
import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
import Text from '@components/Text';
import Tooltip from '@components/Tooltip/PopoverAnchorTooltip';
-import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import useLocalize from '@hooks/useLocalize';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import getButtonState from '@libs/getButtonState';
import variables from '@styles/variables';
import * as EmojiPickerAction from '@userActions/EmojiPickerAction';
+import type {AnchorOrigin} from '@userActions/EmojiPickerAction';
import * as Session from '@userActions/Session';
import CONST from '@src/CONST';
+import type {ReportAction} from '@src/types/onyx';
+import type {CloseContextMenuCallback, OpenPickerCallback, PickerRefElement} from './QuickEmojiReactions/types';
-const propTypes = {
+type AddReactionBubbleProps = {
/** Whether it is for context menu so we can modify its style */
- isContextMenu: PropTypes.bool,
+ isContextMenu?: boolean;
/**
* Called when the user presses on the icon button.
* Will have a function as parameter which you can call
* to open the picker.
*/
- onPressOpenPicker: PropTypes.func,
+ onPressOpenPicker?: (openPicker: OpenPickerCallback) => void;
/**
* Will get called the moment before the picker opens.
*/
- onWillShowPicker: PropTypes.func,
+ onWillShowPicker?: (callback: CloseContextMenuCallback) => void;
/**
* Called when the user selects an emoji.
*/
- onSelectEmoji: PropTypes.func.isRequired,
+ onSelectEmoji: (emoji: Emoji) => void;
/**
* ReportAction for EmojiPicker.
*/
- reportAction: PropTypes.shape({
- reportActionID: PropTypes.string.isRequired,
- }),
-
- ...withLocalizePropTypes,
-};
-
-const defaultProps = {
- isContextMenu: false,
- onWillShowPicker: () => {},
- onPressOpenPicker: undefined,
- reportAction: {},
+ reportAction: ReportAction;
};
-function AddReactionBubble(props) {
+function AddReactionBubble({onSelectEmoji, reportAction, onPressOpenPicker, onWillShowPicker = () => {}, isContextMenu = false}: AddReactionBubbleProps) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
- const ref = useRef();
+ const ref = useRef(null);
+ const {translate} = useLocalize();
+
useEffect(() => EmojiPickerAction.resetEmojiPopoverAnchor, []);
const onPress = () => {
- const openPicker = (refParam, anchorOrigin) => {
+ const openPicker = (refParam?: PickerRefElement, anchorOrigin?: AnchorOrigin) => {
EmojiPickerAction.showEmojiPicker(
() => {},
(emojiCode, emojiObject) => {
- props.onSelectEmoji(emojiObject);
+ onSelectEmoji(emojiObject);
},
- refParam || ref,
+ refParam ?? ref,
anchorOrigin,
- props.onWillShowPicker,
- props.reportAction.reportActionID,
+ onWillShowPicker,
+ reportAction.reportActionID,
);
};
- if (!EmojiPickerAction.emojiPickerRef.current.isEmojiPickerVisible) {
- if (props.onPressOpenPicker) {
- props.onPressOpenPicker(openPicker);
+ if (!EmojiPickerAction.emojiPickerRef.current?.isEmojiPickerVisible) {
+ if (onPressOpenPicker) {
+ onPressOpenPicker(openPicker);
} else {
openPicker();
}
@@ -85,21 +79,21 @@ function AddReactionBubble(props) {
};
return (
-
+ [styles.emojiReactionBubble, styles.userSelectNone, StyleUtils.getEmojiReactionBubbleStyle(hovered || pressed, false, props.isContextMenu)]}
+ style={({hovered, pressed}) => [styles.emojiReactionBubble, styles.userSelectNone, StyleUtils.getEmojiReactionBubbleStyle(hovered || pressed, false, isContextMenu)]}
onPress={Session.checkIfActionIsAllowed(onPress)}
- onMouseDown={(e) => {
+ onMouseDown={(event) => {
// Allow text input blur when Add reaction is right clicked
- if (!e || e.button === 2) {
+ if (!event || event.button === 2) {
return;
}
// Prevent text input blur when Add reaction is left clicked
- e.preventDefault();
+ event.preventDefault();
}}
- accessibilityLabel={props.translate('emojiReactions.addReactionTooltip')}
+ accessibilityLabel={translate('emojiReactions.addReactionTooltip')}
role={CONST.ROLE.BUTTON}
// disable dimming
pressDimmingValue={1}
@@ -110,12 +104,12 @@ function AddReactionBubble(props) {
{/* This (invisible) text will make the view have the same size as a regular
emoji reaction. We make the text invisible and put the
icon on top of it. */}
- {'\u2800\u2800'}
+ {'\u2800\u2800'}
@@ -126,8 +120,6 @@ function AddReactionBubble(props) {
);
}
-AddReactionBubble.propTypes = propTypes;
-AddReactionBubble.defaultProps = defaultProps;
AddReactionBubble.displayName = 'AddReactionBubble';
-export default withLocalize(AddReactionBubble);
+export default AddReactionBubble;
diff --git a/src/components/Reactions/EmojiReactionBubble.js b/src/components/Reactions/EmojiReactionBubble.js
deleted file mode 100644
index 3fd22a758f67..000000000000
--- a/src/components/Reactions/EmojiReactionBubble.js
+++ /dev/null
@@ -1,110 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import PressableWithSecondaryInteraction from '@components/PressableWithSecondaryInteraction';
-import Text from '@components/Text';
-import {withCurrentUserPersonalDetailsDefaultProps} from '@components/withCurrentUserPersonalDetails';
-import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
-import useStyleUtils from '@hooks/useStyleUtils';
-import useThemeStyles from '@hooks/useThemeStyles';
-import CONST from '@src/CONST';
-
-const propTypes = {
- /**
- * The emoji codes to display in the bubble.
- */
- emojiCodes: PropTypes.arrayOf(PropTypes.string).isRequired,
-
- /**
- * Called when the user presses on the reaction bubble.
- */
- onPress: PropTypes.func.isRequired,
-
- /**
- * Called when the user long presses or right clicks
- * on the reaction bubble.
- */
- onReactionListOpen: PropTypes.func,
-
- /**
- * The number of reactions to display in the bubble.
- */
- count: PropTypes.number,
-
- /** Whether it is for context menu so we can modify its style */
- isContextMenu: PropTypes.bool,
-
- /**
- * Returns true if the current account has reacted to the report action (with the given skin tone).
- */
- hasUserReacted: PropTypes.bool,
-
- /** We disable reacting with emojis on report actions that have errors */
- shouldBlockReactions: PropTypes.bool,
-
- ...windowDimensionsPropTypes,
-};
-
-const defaultProps = {
- count: 0,
- onReactionListOpen: () => {},
- isContextMenu: false,
- shouldBlockReactions: false,
-
- ...withCurrentUserPersonalDetailsDefaultProps,
-};
-
-function EmojiReactionBubble(props) {
- const styles = useThemeStyles();
- const StyleUtils = useStyleUtils();
- return (
- [
- styles.emojiReactionBubble,
- StyleUtils.getEmojiReactionBubbleStyle(hovered || pressed, props.hasUserReacted, props.isContextMenu),
- props.shouldBlockReactions && styles.cursorDisabled,
- styles.userSelectNone,
- ]}
- onPress={() => {
- if (props.shouldBlockReactions) {
- return;
- }
-
- props.onPress();
- }}
- onSecondaryInteraction={props.onReactionListOpen}
- ref={props.forwardedRef}
- enableLongPressWithHover={props.isSmallScreenWidth}
- onMouseDown={(e) => {
- // Allow text input blur when emoji reaction is right clicked
- if (e && e.button === 2) {
- return;
- }
-
- // Prevent text input blur when emoji reaction is left clicked
- e.preventDefault();
- }}
- role={CONST.ROLE.BUTTON}
- accessibilityLabel={props.emojiCodes.join('')}
- dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
- >
- {props.emojiCodes.join('')}
- {props.count > 0 && {props.count}}
-
- );
-}
-
-EmojiReactionBubble.propTypes = propTypes;
-EmojiReactionBubble.defaultProps = defaultProps;
-EmojiReactionBubble.displayName = 'EmojiReactionBubble';
-
-const EmojiReactionBubbleWithRef = React.forwardRef((props, ref) => (
-
-));
-
-EmojiReactionBubbleWithRef.displayName = 'EmojiReactionBubbleWithRef';
-
-export default withWindowDimensions(EmojiReactionBubbleWithRef);
diff --git a/src/components/Reactions/EmojiReactionBubble.tsx b/src/components/Reactions/EmojiReactionBubble.tsx
new file mode 100644
index 000000000000..d83689de2dc1
--- /dev/null
+++ b/src/components/Reactions/EmojiReactionBubble.tsx
@@ -0,0 +1,93 @@
+import React from 'react';
+import type {PressableRef} from '@components/Pressable/GenericPressable/types';
+import PressableWithSecondaryInteraction from '@components/PressableWithSecondaryInteraction';
+import Text from '@components/Text';
+import useStyleUtils from '@hooks/useStyleUtils';
+import useThemeStyles from '@hooks/useThemeStyles';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import type {ReactionListEvent} from '@pages/home/ReportScreenContext';
+import CONST from '@src/CONST';
+
+type EmojiReactionBubbleProps = {
+ /**
+ * The emoji codes to display in the bubble.
+ */
+ emojiCodes: string[];
+
+ /**
+ * Called when the user presses on the reaction bubble.
+ */
+ onPress: () => void;
+
+ /**
+ * Called when the user long presses or right clicks
+ * on the reaction bubble.
+ */
+ onReactionListOpen?: (event: ReactionListEvent) => void;
+
+ /**
+ * The number of reactions to display in the bubble.
+ */
+ count?: number;
+
+ /** Whether it is for context menu so we can modify its style */
+ isContextMenu?: boolean;
+
+ /**
+ * Returns true if the current account has reacted to the report action (with the given skin tone).
+ */
+ hasUserReacted?: boolean;
+
+ /** We disable reacting with emojis on report actions that have errors */
+ shouldBlockReactions?: boolean;
+};
+
+function EmojiReactionBubble(
+ {onPress, onReactionListOpen = () => {}, emojiCodes, hasUserReacted = false, count = 0, isContextMenu = false, shouldBlockReactions = false}: EmojiReactionBubbleProps,
+ ref: PressableRef,
+) {
+ const styles = useThemeStyles();
+ const StyleUtils = useStyleUtils();
+ const {isSmallScreenWidth} = useWindowDimensions();
+
+ return (
+ [
+ styles.emojiReactionBubble,
+ StyleUtils.getEmojiReactionBubbleStyle(hovered || pressed, hasUserReacted, isContextMenu),
+ shouldBlockReactions && styles.cursorDisabled,
+ styles.userSelectNone,
+ ]}
+ onPress={() => {
+ if (shouldBlockReactions) {
+ return;
+ }
+
+ onPress();
+ }}
+ onSecondaryInteraction={onReactionListOpen}
+ ref={ref}
+ enableLongPressWithHover={isSmallScreenWidth}
+ onMouseDown={(event) => {
+ // Allow text input blur when emoji reaction is right clicked
+ if (event?.button === 2) {
+ return;
+ }
+
+ // Prevent text input blur when emoji reaction is left clicked
+ event.preventDefault();
+ }}
+ role={CONST.ROLE.BUTTON}
+ accessibilityLabel={emojiCodes.join('')}
+ accessible
+ dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
+ >
+ {emojiCodes.join('')}
+ {count > 0 && {count}}
+
+ );
+}
+
+EmojiReactionBubble.displayName = 'EmojiReactionBubble';
+
+export default React.forwardRef(EmojiReactionBubble);
diff --git a/src/components/Reactions/MiniQuickEmojiReactions.js b/src/components/Reactions/MiniQuickEmojiReactions.tsx
similarity index 56%
rename from src/components/Reactions/MiniQuickEmojiReactions.js
rename to src/components/Reactions/MiniQuickEmojiReactions.tsx
index 376afcb9ade5..9f38da6bdb3d 100644
--- a/src/components/Reactions/MiniQuickEmojiReactions.js
+++ b/src/components/Reactions/MiniQuickEmojiReactions.tsx
@@ -1,49 +1,38 @@
-import PropTypes from 'prop-types';
import React, {useRef} from 'react';
import {View} from 'react-native';
+import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
-import _ from 'underscore';
+import type {Emoji} from '@assets/emojis/types';
import BaseMiniContextMenuItem from '@components/BaseMiniContextMenuItem';
import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';
import Text from '@components/Text';
-import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import useLocalize from '@hooks/useLocalize';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
-import compose from '@libs/compose';
import * as EmojiUtils from '@libs/EmojiUtils';
import getButtonState from '@libs/getButtonState';
import * as EmojiPickerAction from '@userActions/EmojiPickerAction';
import * as Session from '@userActions/Session';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
-import {baseQuickEmojiReactionsDefaultProps, baseQuickEmojiReactionsPropTypes} from './QuickEmojiReactions/BaseQuickEmojiReactions';
+import type {ReportActionReactions} from '@src/types/onyx';
+import type {BaseQuickEmojiReactionsProps} from './QuickEmojiReactions/types';
-const propTypes = {
- ...baseQuickEmojiReactionsPropTypes,
+type MiniQuickEmojiReactionsOnyxProps = {
+ /** All the emoji reactions for the report action. */
+ emojiReactions: OnyxEntry;
+ /** The user's preferred skin tone. */
+ preferredSkinTone: OnyxEntry;
+};
+
+type MiniQuickEmojiReactionsProps = BaseQuickEmojiReactionsProps & {
/**
* Will be called when the user closed the emoji picker
* without selecting an emoji.
*/
- onEmojiPickerClosed: PropTypes.func,
-
- /**
- * ReportAction for EmojiPicker.
- */
- reportAction: PropTypes.shape({
- reportActionID: PropTypes.string.isRequired,
- }),
-
- ...withLocalizePropTypes,
- preferredSkinTone: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
-};
-
-const defaultProps = {
- ...baseQuickEmojiReactionsDefaultProps,
- onEmojiPickerClosed: () => {},
- preferredSkinTone: CONST.EMOJI_DEFAULT_SKIN_TONE,
- reportAction: {},
+ onEmojiPickerClosed?: () => void;
};
/**
@@ -51,56 +40,63 @@ const defaultProps = {
* emoji picker icon button. This is used for the mini
* context menu which we just show on web, when hovering
* a message.
- * @param {Props} props
- * @returns {JSX.Element}
*/
-function MiniQuickEmojiReactions(props) {
+function MiniQuickEmojiReactions({
+ reportAction,
+ onEmojiSelected,
+ preferredLocale = CONST.LOCALES.DEFAULT,
+ preferredSkinTone = CONST.EMOJI_DEFAULT_SKIN_TONE,
+ emojiReactions = {},
+ onPressOpenPicker = () => {},
+ onEmojiPickerClosed = () => {},
+}: MiniQuickEmojiReactionsProps) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
- const ref = useRef();
+ const ref = useRef(null);
+ const {translate} = useLocalize();
const openEmojiPicker = () => {
- props.onPressOpenPicker();
+ onPressOpenPicker();
EmojiPickerAction.showEmojiPicker(
- props.onEmojiPickerClosed,
+ onEmojiPickerClosed,
(emojiCode, emojiObject) => {
- props.onEmojiSelected(emojiObject, props.emojiReactions);
+ onEmojiSelected(emojiObject, emojiReactions);
},
ref,
undefined,
() => {},
- props.reportAction.reportActionID,
+ reportAction.reportActionID,
);
};
return (
- {_.map(CONST.QUICK_REACTIONS, (emoji) => (
+ {CONST.QUICK_REACTIONS.map((emoji: Emoji) => (
props.onEmojiSelected(emoji, props.emojiReactions))}
+ tooltipText={`:${EmojiUtils.getLocalizedEmojiName(emoji.name, preferredLocale)}:`}
+ onPress={Session.checkIfActionIsAllowed(() => onEmojiSelected(emoji, emojiReactions))}
>
- {EmojiUtils.getPreferredEmojiCode(emoji, props.preferredSkinTone)}
+ {EmojiUtils.getPreferredEmojiCode(emoji, preferredSkinTone)}
))}
{
- if (!EmojiPickerAction.emojiPickerRef.current.isEmojiPickerVisible) {
+ if (!EmojiPickerAction.emojiPickerRef.current?.isEmojiPickerVisible) {
openEmojiPicker();
} else {
- EmojiPickerAction.emojiPickerRef.current.hideEmojiPicker();
+ EmojiPickerAction.emojiPickerRef.current?.hideEmojiPicker();
}
})}
isDelayButtonStateComplete={false}
- tooltipText={props.translate('emojiReactions.addReactionTooltip')}
+ tooltipText={translate('emojiReactions.addReactionTooltip')}
>
{({hovered, pressed}) => (
`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_REACTIONS}${reportActionID}`,
- },
- }),
-)(MiniQuickEmojiReactions);
+
+export default withOnyx({
+ preferredSkinTone: {
+ key: ONYXKEYS.PREFERRED_EMOJI_SKIN_TONE,
+ },
+ emojiReactions: {
+ key: ({reportActionID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS_REACTIONS}${reportActionID}`,
+ },
+})(MiniQuickEmojiReactions);
diff --git a/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js b/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js
deleted file mode 100644
index c932632f7bff..000000000000
--- a/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js
+++ /dev/null
@@ -1,106 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import {View} from 'react-native';
-import {withOnyx} from 'react-native-onyx';
-import _ from 'underscore';
-import AddReactionBubble from '@components/Reactions/AddReactionBubble';
-import EmojiReactionBubble from '@components/Reactions/EmojiReactionBubble';
-import EmojiReactionsPropTypes from '@components/Reactions/EmojiReactionsPropTypes';
-import Tooltip from '@components/Tooltip';
-import useThemeStyles from '@hooks/useThemeStyles';
-import * as EmojiUtils from '@libs/EmojiUtils';
-import * as Session from '@userActions/Session';
-import CONST from '@src/CONST';
-import ONYXKEYS from '@src/ONYXKEYS';
-
-const baseQuickEmojiReactionsPropTypes = {
- emojiReactions: EmojiReactionsPropTypes,
-
- /**
- * Callback to fire when an emoji is selected.
- */
- onEmojiSelected: PropTypes.func.isRequired,
-
- /**
- * Will be called when the emoji picker is about to show.
- */
- onWillShowPicker: PropTypes.func,
-
- /**
- * Callback to fire when the "open emoji picker" button is pressed.
- * The function receives an argument which can be called
- * to actually open the emoji picker.
- */
- onPressOpenPicker: PropTypes.func,
-
- /**
- * ReportAction for EmojiPicker.
- */
- reportAction: PropTypes.object,
-
- preferredLocale: PropTypes.string,
-};
-
-const baseQuickEmojiReactionsDefaultProps = {
- emojiReactions: {},
- onWillShowPicker: () => {},
- onPressOpenPicker: () => {},
- reportAction: {},
- preferredLocale: CONST.LOCALES.DEFAULT,
-};
-
-const propTypes = {
- ...baseQuickEmojiReactionsPropTypes,
- preferredSkinTone: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
-};
-
-const defaultProps = {
- ...baseQuickEmojiReactionsDefaultProps,
- preferredSkinTone: CONST.EMOJI_DEFAULT_SKIN_TONE,
-};
-
-function BaseQuickEmojiReactions(props) {
- const styles = useThemeStyles();
- return (
-
- {_.map(CONST.QUICK_REACTIONS, (emoji) => (
-
-
- props.onEmojiSelected(emoji, props.emojiReactions))}
- />
-
-
- ))}
- props.onEmojiSelected(emoji, props.emojiReactions)}
- reportAction={props.reportAction}
- />
-
- );
-}
-
-BaseQuickEmojiReactions.displayName = 'BaseQuickEmojiReactions';
-BaseQuickEmojiReactions.propTypes = propTypes;
-BaseQuickEmojiReactions.defaultProps = defaultProps;
-export default withOnyx({
- preferredSkinTone: {
- key: ONYXKEYS.PREFERRED_EMOJI_SKIN_TONE,
- },
- emojiReactions: {
- key: ({reportActionID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS_REACTIONS}${reportActionID}`,
- },
- preferredLocale: {
- key: ONYXKEYS.NVP_PREFERRED_LOCALE,
- },
-})(BaseQuickEmojiReactions);
-
-export {baseQuickEmojiReactionsPropTypes, baseQuickEmojiReactionsDefaultProps};
diff --git a/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.tsx b/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.tsx
new file mode 100644
index 000000000000..58973e90b9c4
--- /dev/null
+++ b/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.tsx
@@ -0,0 +1,65 @@
+import React from 'react';
+import {View} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
+import type {Emoji} from '@assets/emojis/types';
+import AddReactionBubble from '@components/Reactions/AddReactionBubble';
+import EmojiReactionBubble from '@components/Reactions/EmojiReactionBubble';
+import Tooltip from '@components/Tooltip';
+import useThemeStyles from '@hooks/useThemeStyles';
+import * as EmojiUtils from '@libs/EmojiUtils';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import type {BaseQuickEmojiReactionsOnyxProps, BaseQuickEmojiReactionsProps} from './types';
+
+function BaseQuickEmojiReactions({
+ reportAction,
+ onEmojiSelected,
+ preferredLocale = CONST.LOCALES.DEFAULT,
+ preferredSkinTone = CONST.EMOJI_DEFAULT_SKIN_TONE,
+ emojiReactions = {},
+ onPressOpenPicker = () => {},
+ onWillShowPicker = () => {},
+}: BaseQuickEmojiReactionsProps) {
+ const styles = useThemeStyles();
+
+ return (
+
+ {CONST.QUICK_REACTIONS.map((emoji: Emoji) => (
+
+
+ onEmojiSelected(emoji, emojiReactions))}
+ />
+
+
+ ))}
+ onEmojiSelected(emoji, emojiReactions)}
+ reportAction={reportAction}
+ />
+
+ );
+}
+
+BaseQuickEmojiReactions.displayName = 'BaseQuickEmojiReactions';
+
+export default withOnyx({
+ preferredSkinTone: {
+ key: ONYXKEYS.PREFERRED_EMOJI_SKIN_TONE,
+ },
+ emojiReactions: {
+ key: ({reportActionID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS_REACTIONS}${reportActionID}`,
+ },
+ preferredLocale: {
+ key: ONYXKEYS.NVP_PREFERRED_LOCALE,
+ },
+})(BaseQuickEmojiReactions);
diff --git a/src/components/Reactions/QuickEmojiReactions/index.js b/src/components/Reactions/QuickEmojiReactions/index.js
deleted file mode 100644
index 0366071f9c81..000000000000
--- a/src/components/Reactions/QuickEmojiReactions/index.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import {contextMenuRef} from '@pages/home/report/ContextMenu/ReportActionContextMenu';
-import CONST from '@src/CONST';
-import BaseQuickEmojiReactions, {baseQuickEmojiReactionsPropTypes} from './BaseQuickEmojiReactions';
-
-const propTypes = {
- ...baseQuickEmojiReactionsPropTypes,
-
- /**
- * Function that can be called to close the
- * context menu in which this component is
- * rendered.
- */
- closeContextMenu: PropTypes.func.isRequired,
-};
-
-function QuickEmojiReactions(props) {
- const onPressOpenPicker = (openPicker) => {
- openPicker(contextMenuRef.current.contentRef, {
- horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT,
- vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP,
- });
- };
-
- return (
-
- );
-}
-
-QuickEmojiReactions.displayName = 'QuickEmojiReactions';
-QuickEmojiReactions.propTypes = propTypes;
-export default QuickEmojiReactions;
diff --git a/src/components/Reactions/QuickEmojiReactions/index.native.js b/src/components/Reactions/QuickEmojiReactions/index.native.tsx
similarity index 56%
rename from src/components/Reactions/QuickEmojiReactions/index.native.js
rename to src/components/Reactions/QuickEmojiReactions/index.native.tsx
index c29bd2665e4a..b0eb88b31b68 100644
--- a/src/components/Reactions/QuickEmojiReactions/index.native.js
+++ b/src/components/Reactions/QuickEmojiReactions/index.native.tsx
@@ -1,41 +1,30 @@
-import PropTypes from 'prop-types';
import React from 'react';
import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager';
-import BaseQuickEmojiReactions, {baseQuickEmojiReactionsPropTypes} from './BaseQuickEmojiReactions';
+import BaseQuickEmojiReactions from './BaseQuickEmojiReactions';
+import type {OpenPickerCallback, QuickEmojiReactionsProps} from './types';
-const propTypes = {
- ...baseQuickEmojiReactionsPropTypes,
-
- /**
- * Function that can be called to close the
- * context menu in which this component is
- * rendered.
- */
- closeContextMenu: PropTypes.func.isRequired,
-};
-
-function QuickEmojiReactions(props) {
- const onPressOpenPicker = (openPicker) => {
+function QuickEmojiReactions({closeContextMenu, ...rest}: QuickEmojiReactionsProps) {
+ const onPressOpenPicker = (openPicker?: OpenPickerCallback) => {
// We first need to close the menu as it's a popover.
// The picker is a popover as well and on mobile there can only
// be one active popover at a time.
- props.closeContextMenu(() => {
+ closeContextMenu(() => {
// As the menu which includes the button to open the emoji picker
// gets closed, before the picker actually opens, we pass the composer
// ref as anchor for the emoji picker popover.
- openPicker(ReportActionComposeFocusManager.composerRef);
+ openPicker?.(ReportActionComposeFocusManager.composerRef);
});
};
return (
);
}
QuickEmojiReactions.displayName = 'QuickEmojiReactions';
-QuickEmojiReactions.propTypes = propTypes;
+
export default QuickEmojiReactions;
diff --git a/src/components/Reactions/QuickEmojiReactions/index.tsx b/src/components/Reactions/QuickEmojiReactions/index.tsx
new file mode 100644
index 000000000000..3b44f4fe4826
--- /dev/null
+++ b/src/components/Reactions/QuickEmojiReactions/index.tsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import {contextMenuRef} from '@pages/home/report/ContextMenu/ReportActionContextMenu';
+import CONST from '@src/CONST';
+import BaseQuickEmojiReactions from './BaseQuickEmojiReactions';
+import type {OpenPickerCallback, QuickEmojiReactionsProps} from './types';
+
+function QuickEmojiReactions({closeContextMenu, ...rest}: QuickEmojiReactionsProps) {
+ const onPressOpenPicker = (openPicker?: OpenPickerCallback) => {
+ openPicker?.(contextMenuRef.current?.contentRef, {
+ horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT,
+ vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP,
+ });
+ };
+
+ return (
+
+ );
+}
+
+QuickEmojiReactions.displayName = 'QuickEmojiReactions';
+
+export default QuickEmojiReactions;
diff --git a/src/components/Reactions/QuickEmojiReactions/types.ts b/src/components/Reactions/QuickEmojiReactions/types.ts
new file mode 100644
index 000000000000..d782d5ae35c7
--- /dev/null
+++ b/src/components/Reactions/QuickEmojiReactions/types.ts
@@ -0,0 +1,56 @@
+import type {RefObject} from 'react';
+import type {TextInput, View} from 'react-native';
+import type {OnyxEntry} from 'react-native-onyx';
+import type {Emoji} from '@assets/emojis/types';
+import type {AnchorOrigin} from '@userActions/EmojiPickerAction';
+import type {Locale, ReportAction, ReportActionReactions} from '@src/types/onyx';
+
+type PickerRefElement = RefObject;
+
+type OpenPickerCallback = (element?: PickerRefElement, anchorOrigin?: AnchorOrigin) => void;
+
+type CloseContextMenuCallback = () => void;
+
+type BaseQuickEmojiReactionsOnyxProps = {
+ /** All the emoji reactions for the report action. */
+ emojiReactions: OnyxEntry;
+
+ /** The user's preferred locale. */
+ preferredLocale: OnyxEntry;
+
+ /** The user's preferred skin tone. */
+ preferredSkinTone: OnyxEntry;
+};
+
+type BaseQuickEmojiReactionsProps = BaseQuickEmojiReactionsOnyxProps & {
+ /** Callback to fire when an emoji is selected. */
+ onEmojiSelected: (emoji: Emoji, emojiReactions: OnyxEntry) => void;
+
+ /**
+ * Will be called when the emoji picker is about to show.
+ */
+ onWillShowPicker?: (callback: CloseContextMenuCallback) => void;
+
+ /**
+ * Callback to fire when the "open emoji picker" button is pressed.
+ * The function receives an argument which can be called
+ * to actually open the emoji picker.
+ */
+ onPressOpenPicker?: (openPicker?: OpenPickerCallback) => void;
+
+ /** ReportAction for EmojiPicker. */
+ reportAction: ReportAction;
+
+ /** Id of the ReportAction for EmojiPicker. */
+ reportActionID: string;
+};
+
+type QuickEmojiReactionsProps = BaseQuickEmojiReactionsProps & {
+ /**
+ * Function that can be called to close the context menu
+ * in which this component is rendered.
+ */
+ closeContextMenu: (callback: CloseContextMenuCallback) => void;
+};
+
+export type {BaseQuickEmojiReactionsProps, BaseQuickEmojiReactionsOnyxProps, QuickEmojiReactionsProps, OpenPickerCallback, CloseContextMenuCallback, PickerRefElement};
diff --git a/src/components/Reactions/ReactionTooltipContent.js b/src/components/Reactions/ReactionTooltipContent.js
deleted file mode 100644
index bb6b03c5918b..000000000000
--- a/src/components/Reactions/ReactionTooltipContent.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import PropTypes from 'prop-types';
-import React, {useMemo} from 'react';
-import {View} from 'react-native';
-import _ from 'underscore';
-import Text from '@components/Text';
-import {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
-import withLocalize from '@components/withLocalize';
-import useThemeStyles from '@hooks/useThemeStyles';
-import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
-
-const propTypes = {
- /**
- * A list of emoji codes to display in the tooltip.
- */
- emojiCodes: PropTypes.arrayOf(PropTypes.string).isRequired,
-
- /**
- * The name of the emoji to display in the tooltip.
- */
- emojiName: PropTypes.string.isRequired,
-
- /**
- * A list of account IDs to display in the tooltip.
- */
- accountIDs: PropTypes.arrayOf(PropTypes.number).isRequired,
-
- ...withCurrentUserPersonalDetailsPropTypes,
-};
-
-const defaultProps = {
- ...withCurrentUserPersonalDetailsDefaultProps,
-};
-
-function ReactionTooltipContent(props) {
- const styles = useThemeStyles();
- const users = useMemo(
- () => PersonalDetailsUtils.getPersonalDetailsByIDs(props.accountIDs, props.currentUserPersonalDetails.accountID, true),
- [props.currentUserPersonalDetails.accountID, props.accountIDs],
- );
- const namesString = _.filter(
- _.map(users, (user) => user && user.displayName),
- (n) => n,
- ).join(', ');
- return (
-
-
- {_.map(props.emojiCodes, (emojiCode) => (
-
- {emojiCode}
-
- ))}
-
-
- {namesString}
-
- {`${props.translate('emojiReactions.reactedWith')} :${props.emojiName}:`}
-
- );
-}
-
-ReactionTooltipContent.propTypes = propTypes;
-ReactionTooltipContent.defaultProps = defaultProps;
-ReactionTooltipContent.displayName = 'ReactionTooltipContent';
-export default React.memo(withLocalize(ReactionTooltipContent));
diff --git a/src/components/Reactions/ReactionTooltipContent.tsx b/src/components/Reactions/ReactionTooltipContent.tsx
new file mode 100644
index 000000000000..198eba1f969c
--- /dev/null
+++ b/src/components/Reactions/ReactionTooltipContent.tsx
@@ -0,0 +1,58 @@
+import React, {useMemo} from 'react';
+import {View} from 'react-native';
+import Text from '@components/Text';
+import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
+
+type ReactionTooltipContentProps = Pick & {
+ /**
+ * A list of emoji codes to display in the tooltip.
+ */
+ emojiCodes: string[];
+
+ /**
+ * The name of the emoji to display in the tooltip.
+ */
+ emojiName: string;
+
+ /**
+ * A list of account IDs to display in the tooltip.
+ */
+ accountIDs: number[];
+};
+
+function ReactionTooltipContent({accountIDs, currentUserPersonalDetails = {}, emojiCodes, emojiName}: ReactionTooltipContentProps) {
+ const styles = useThemeStyles();
+ const {translate} = useLocalize();
+ const users = useMemo(() => PersonalDetailsUtils.getPersonalDetailsByIDs(accountIDs, currentUserPersonalDetails.accountID, true), [currentUserPersonalDetails.accountID, accountIDs]);
+
+ const namesString = users
+ .map((user) => user?.displayName)
+ .filter((name) => name)
+ .join(', ');
+
+ return (
+
+
+ {emojiCodes.map((emojiCode) => (
+
+ {emojiCode}
+
+ ))}
+
+
+ {namesString}
+
+ {`${translate('emojiReactions.reactedWith')} :${emojiName}:`}
+
+ );
+}
+
+ReactionTooltipContent.displayName = 'ReactionTooltipContent';
+
+export default React.memo(ReactionTooltipContent);
diff --git a/src/components/Reactions/ReportActionItemEmojiReactions.js b/src/components/Reactions/ReportActionItemEmojiReactions.tsx
similarity index 52%
rename from src/components/Reactions/ReportActionItemEmojiReactions.js
rename to src/components/Reactions/ReportActionItemEmojiReactions.tsx
index 547f4089857f..69779dc316e1 100644
--- a/src/components/Reactions/ReportActionItemEmojiReactions.js
+++ b/src/components/Reactions/ReportActionItemEmojiReactions.tsx
@@ -1,63 +1,98 @@
-import lodashGet from 'lodash/get';
-import PropTypes from 'prop-types';
+import sortBy from 'lodash/sortBy';
import React, {useContext, useRef} from 'react';
import {View} from 'react-native';
-import _ from 'underscore';
+import type {OnyxEntry} from 'react-native-onyx';
+import type {Emoji} from '@assets/emojis/types';
import OfflineWithFeedback from '@components/OfflineWithFeedback';
import Tooltip from '@components/Tooltip';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
-import withLocalize from '@components/withLocalize';
+import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails';
+import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails';
import useThemeStyles from '@hooks/useThemeStyles';
-import compose from '@libs/compose';
import * as EmojiUtils from '@libs/EmojiUtils';
-import reportActionPropTypes from '@pages/home/report/reportActionPropTypes';
import {ReactionListContext} from '@pages/home/ReportScreenContext';
+import type {ReactionListAnchor, ReactionListEvent} from '@pages/home/ReportScreenContext';
+import CONST from '@src/CONST';
+import type {Locale, ReportAction, ReportActionReactions} from '@src/types/onyx';
+import type {PendingAction} from '@src/types/onyx/OnyxCommon';
import AddReactionBubble from './AddReactionBubble';
import EmojiReactionBubble from './EmojiReactionBubble';
-import EmojiReactionsPropTypes from './EmojiReactionsPropTypes';
import ReactionTooltipContent from './ReactionTooltipContent';
-const propTypes = {
- emojiReactions: EmojiReactionsPropTypes,
+type ReportActionItemEmojiReactionsProps = WithCurrentUserPersonalDetailsProps & {
+ /** All the emoji reactions for the report action. */
+ emojiReactions: OnyxEntry;
+
+ /** The user's preferred locale. */
+ preferredLocale: OnyxEntry;
/** The report action that these reactions are for */
- reportAction: PropTypes.shape(reportActionPropTypes).isRequired,
+ reportAction: ReportAction;
/**
* Function to call when the user presses on an emoji.
* This can also be an emoji the user already reacted with,
* hence this function asks to toggle the reaction by emoji.
*/
- toggleReaction: PropTypes.func.isRequired,
+ toggleReaction: (emoji: Emoji) => void;
/** We disable reacting with emojis on report actions that have errors */
- shouldBlockReactions: PropTypes.bool,
-
- ...withCurrentUserPersonalDetailsPropTypes,
+ shouldBlockReactions?: boolean;
};
-const defaultProps = {
- ...withCurrentUserPersonalDetailsDefaultProps,
- emojiReactions: {},
- shouldBlockReactions: false,
+type PopoverReactionListAnchors = Record;
+
+type FormattedReaction = {
+ /** The emoji codes to display in the bubble */
+ emojiCodes: string[];
+
+ /** IDs of users used the reaction */
+ userAccountIDs: number[];
+
+ /** Total reaction count */
+ reactionCount: number;
+
+ /** Whether the current account has reacted to the report action */
+ hasUserReacted: boolean;
+
+ /** Oldest timestamp of when the emoji was added */
+ oldestTimestamp: string;
+
+ /** Callback to fire on press */
+ onPress: () => void;
+
+ /** Callback to fire on reaction list open */
+ onReactionListOpen: (event: ReactionListEvent) => void;
+
+ /** The name of the emoji */
+ reactionEmojiName: string;
+
+ /** The type of action that's pending */
+ pendingAction?: PendingAction;
};
-function ReportActionItemEmojiReactions(props) {
+function ReportActionItemEmojiReactions({
+ reportAction,
+ currentUserPersonalDetails,
+ toggleReaction,
+ emojiReactions = {},
+ shouldBlockReactions = false,
+ preferredLocale = CONST.LOCALES.DEFAULT,
+}: ReportActionItemEmojiReactionsProps) {
const styles = useThemeStyles();
const reactionListRef = useContext(ReactionListContext);
- const popoverReactionListAnchors = useRef({});
+ const popoverReactionListAnchors = useRef({});
let totalReactionCount = 0;
- const reportAction = props.reportAction;
const reportActionID = reportAction.reportActionID;
- const formattedReactions = _.chain(props.emojiReactions)
- .map((emojiReaction, emojiName) => {
+ // Each emoji is sorted by the oldest timestamp of user reactions so that they will always appear in the same order for everyone
+ const formattedReactions: Array = sortBy(
+ Object.entries(emojiReactions ?? {}).map(([emojiName, emojiReaction]) => {
const {emoji, emojiCodes, reactionCount, hasUserReacted, userAccountIDs, oldestTimestamp} = EmojiUtils.getEmojiReactionDetails(
emojiName,
emojiReaction,
- props.currentUserPersonalDetails.accountID,
+ currentUserPersonalDetails.accountID,
);
if (reactionCount === 0) {
@@ -66,11 +101,11 @@ function ReportActionItemEmojiReactions(props) {
totalReactionCount += reactionCount;
const onPress = () => {
- props.toggleReaction(emoji);
+ toggleReaction(emoji);
};
- const onReactionListOpen = (event) => {
- reactionListRef.current.showReactionList(event, popoverReactionListAnchors.current[emojiName], emojiName, reportActionID);
+ const onReactionListOpen = (event: ReactionListEvent) => {
+ reactionListRef?.current?.showReactionList(event, popoverReactionListAnchors.current[emojiName], emojiName, reportActionID);
};
return {
@@ -84,15 +119,14 @@ function ReportActionItemEmojiReactions(props) {
reactionEmojiName: emojiName,
pendingAction: emojiReaction.pendingAction,
};
- })
- // Each emoji is sorted by the oldest timestamp of user reactions so that they will always appear in the same order for everyone
- .sortBy('oldestTimestamp')
- .value();
+ }),
+ ['oldestTimestamp'],
+ );
return (
totalReactionCount > 0 && (
- {_.map(formattedReactions, (reaction) => {
+ {formattedReactions.map((reaction) => {
if (reaction === null) {
return;
}
@@ -100,19 +134,19 @@ function ReportActionItemEmojiReactions(props) {
(
)}
- renderTooltipContentKey={[..._.map(reaction.userAccountIDs, String), ...reaction.emojiCodes]}
+ renderTooltipContentKey={[...reaction.userAccountIDs.map(String), ...reaction.emojiCodes]}
key={reaction.reactionEmojiName}
>
(popoverReactionListAnchors.current[reaction.reactionEmojiName] = ref)}
@@ -121,17 +155,17 @@ function ReportActionItemEmojiReactions(props) {
onPress={reaction.onPress}
hasUserReacted={reaction.hasUserReacted}
onReactionListOpen={reaction.onReactionListOpen}
- shouldBlockReactions={props.shouldBlockReactions}
+ shouldBlockReactions={shouldBlockReactions}
/>
);
})}
- {!props.shouldBlockReactions && (
+ {!shouldBlockReactions && (
)}
@@ -140,6 +174,5 @@ function ReportActionItemEmojiReactions(props) {
}
ReportActionItemEmojiReactions.displayName = 'ReportActionItemReactions';
-ReportActionItemEmojiReactions.propTypes = propTypes;
-ReportActionItemEmojiReactions.defaultProps = defaultProps;
-export default compose(withLocalize, withCurrentUserPersonalDetails)(ReportActionItemEmojiReactions);
+
+export default withCurrentUserPersonalDetails(ReportActionItemEmojiReactions);
diff --git a/src/components/ReportActionItem/ActionableItemButtons.tsx b/src/components/ReportActionItem/ActionableItemButtons.tsx
new file mode 100644
index 000000000000..d1f169d2f409
--- /dev/null
+++ b/src/components/ReportActionItem/ActionableItemButtons.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import {View} from 'react-native';
+import Button from '@components/Button';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import type {TranslationPaths} from '@src/languages/types';
+
+type ActionableItem = {
+ isPrimary?: boolean;
+ key: string;
+ onPress: () => void;
+ text: TranslationPaths;
+};
+
+type ActionableItemButtonsProps = {
+ items: ActionableItem[];
+};
+
+function ActionableItemButtons(props: ActionableItemButtonsProps) {
+ const styles = useThemeStyles();
+ const {translate} = useLocalize();
+
+ return (
+
+ {props.items?.map((item) => (
+
+ ))}
+
+ );
+}
+
+ActionableItemButtons.displayName = 'ActionableItemButtton';
+
+export default ActionableItemButtons;
+export type {ActionableItem};
diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js
index f0e818ddff4d..96c9e1b364d6 100644
--- a/src/components/ReportActionItem/MoneyRequestPreview.js
+++ b/src/components/ReportActionItem/MoneyRequestPreview.js
@@ -1,3 +1,4 @@
+import {truncate} from 'lodash';
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
import React from 'react';
@@ -151,8 +152,9 @@ function MoneyRequestPreview(props) {
// Pay button should only be visible to the manager of the report.
const isCurrentUserManager = managerID === sessionAccountID;
- const {amount: requestAmount, currency: requestCurrency, comment: requestComment, merchant: requestMerchant} = ReportUtils.getTransactionDetails(props.transaction);
- const description = requestComment;
+ const {amount: requestAmount, currency: requestCurrency, comment: requestComment, merchant} = ReportUtils.getTransactionDetails(props.transaction);
+ const description = truncate(requestComment, {length: CONST.REQUEST_PREVIEW.MAX_LENGTH});
+ const requestMerchant = truncate(merchant, {length: CONST.REQUEST_PREVIEW.MAX_LENGTH});
const hasReceipt = TransactionUtils.hasReceipt(props.transaction);
const isScanning = hasReceipt && TransactionUtils.isReceiptBeingScanned(props.transaction);
const hasFieldErrors = TransactionUtils.hasMissingSmartscanFields(props.transaction);
@@ -208,7 +210,7 @@ function MoneyRequestPreview(props) {
}
let message = translate('iou.cash');
- if (ReportUtils.isGroupPolicyExpenseReport(props.iouReport) && ReportUtils.isReportApproved(props.iouReport) && !ReportUtils.isSettled(props.iouReport)) {
+ if (ReportUtils.isPaidGroupPolicyExpenseReport(props.iouReport) && ReportUtils.isReportApproved(props.iouReport) && !ReportUtils.isSettled(props.iouReport)) {
message += ` • ${translate('iou.approved')}`;
} else if (props.iouReport.isWaitingOnBankAccount) {
message += ` • ${translate('iou.pending')}`;
@@ -220,7 +222,7 @@ function MoneyRequestPreview(props) {
const getDisplayAmountText = () => {
if (isDistanceRequest) {
- return requestAmount && !hasPendingWaypoints ? CurrencyUtils.convertToDisplayString(requestAmount, props.transaction.currency) : translate('common.tbd');
+ return requestAmount && !hasPendingWaypoints ? CurrencyUtils.convertToDisplayString(requestAmount, requestCurrency) : translate('common.tbd');
}
if (isScanning) {
diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js
index 514dc71ffe2c..7c7998c24c95 100644
--- a/src/components/ReportActionItem/MoneyRequestView.js
+++ b/src/components/ReportActionItem/MoneyRequestView.js
@@ -1,7 +1,7 @@
import lodashGet from 'lodash/get';
import lodashValues from 'lodash/values';
import PropTypes from 'prop-types';
-import React, {useMemo} from 'react';
+import React, {useCallback} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import categoryPropTypes from '@components/categoryPropTypes';
@@ -14,12 +14,14 @@ import Switch from '@components/Switch';
import tagPropTypes from '@components/tagPropTypes';
import Text from '@components/Text';
import transactionPropTypes from '@components/transactionPropTypes';
+import ViolationMessages from '@components/ViolationMessages';
import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
import useLocalize from '@hooks/useLocalize';
import usePermissions from '@hooks/usePermissions';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
+import useViolations from '@hooks/useViolations';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as CardUtils from '@libs/CardUtils';
import compose from '@libs/compose';
@@ -35,12 +37,39 @@ import AnimatedEmptyStateBackground from '@pages/home/report/AnimatedEmptyStateB
import reportActionPropTypes from '@pages/home/report/reportActionPropTypes';
import iouReportPropTypes from '@pages/iouReportPropTypes';
import reportPropTypes from '@pages/reportPropTypes';
+import {policyDefaultProps, policyPropTypes} from '@pages/workspace/withPolicy';
import * as IOU from '@userActions/IOU';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import ReportActionItemImage from './ReportActionItemImage';
+const violationNames = lodashValues(CONST.VIOLATIONS);
+
+const transactionViolationPropType = PropTypes.shape({
+ type: PropTypes.string.isRequired,
+ name: PropTypes.oneOf(violationNames).isRequired,
+ data: PropTypes.shape({
+ rejectedBy: PropTypes.string,
+ rejectReason: PropTypes.string,
+ amount: PropTypes.string,
+ surcharge: PropTypes.number,
+ invoiceMarkup: PropTypes.number,
+ maxAge: PropTypes.number,
+ tagName: PropTypes.string,
+ formattedLimitAmount: PropTypes.string,
+ categoryLimit: PropTypes.string,
+ limit: PropTypes.string,
+ category: PropTypes.string,
+ brokenBankConnection: PropTypes.bool,
+ isAdmin: PropTypes.bool,
+ email: PropTypes.string,
+ isTransactionOlderThan7Days: PropTypes.bool,
+ member: PropTypes.string,
+ taxName: PropTypes.string,
+ }),
+});
+
const propTypes = {
/** The report currently being looked at */
report: reportPropTypes.isRequired,
@@ -55,12 +84,18 @@ const propTypes = {
/** The actions from the parent report */
parentReportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)),
+ /** The policy the report is tied to */
+ ...policyPropTypes,
+
/** Collection of categories attached to a policy */
policyCategories: PropTypes.objectOf(categoryPropTypes),
/** The transaction associated with the transactionThread */
transaction: transactionPropTypes,
+ /** Violations detected in this transaction */
+ transactionViolations: PropTypes.arrayOf(transactionViolationPropType),
+
/** Collection of tags attached to a policy */
policyTags: tagPropTypes,
@@ -70,16 +105,18 @@ const propTypes = {
const defaultProps = {
parentReport: {},
parentReportActions: {},
- policyCategories: {},
transaction: {
amount: 0,
currency: CONST.CURRENCY.USD,
comment: {comment: ''},
},
+ transactionViolations: [],
+ policyCategories: {},
policyTags: {},
+ ...policyDefaultProps,
};
-function MoneyRequestView({report, parentReport, parentReportActions, policyCategories, shouldShowHorizontalRule, transaction, policyTags, policy}) {
+function MoneyRequestView({report, parentReport, parentReportActions, policyCategories, shouldShowHorizontalRule, transaction, policyTags, policy, transactionViolations}) {
const theme = useTheme();
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
@@ -115,12 +152,18 @@ function MoneyRequestView({report, parentReport, parentReportActions, policyCate
// Flags for allowing or disallowing editing a money request
const isSettled = ReportUtils.isSettled(moneyRequestReport.reportID);
const isCancelled = moneyRequestReport && moneyRequestReport.isCancelledIOU;
+
+ // Used for non-restricted fields such as: description, category, tag, billable, etc.
const canEdit = ReportUtils.canEditMoneyRequest(parentReportAction);
- const canEditAmount = canEdit && !isSettled && !isCardTransaction;
- const canEditReceipt = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, moneyRequestReport.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT);
+ const canEditAmount = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.AMOUNT);
+ const canEditMerchant = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.MERCHANT);
+ const canEditDate = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.DATE);
+ const canEditReceipt = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.RECEIPT);
+ const canEditDistance = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.DISTANCE);
// A flag for verifying that the current report is a sub-report of a workspace chat
- const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(report)), [report]);
+ // if the policy of the report is either Collect or Control, then this report must be tied to workspace chat
+ const isPolicyExpenseChat = ReportUtils.isGroupPolicy(report);
// Fetches only the first tag, for now
const policyTag = PolicyUtils.getTag(policyTags);
@@ -131,8 +174,24 @@ function MoneyRequestView({report, parentReport, parentReportActions, policyCate
const shouldShowTag = isPolicyExpenseChat && (transactionTag || OptionsListUtils.hasEnabledOptions(lodashValues(policyTagsList)));
const shouldShowBillable = isPolicyExpenseChat && (transactionBillable || !lodashGet(policy, 'disabledFields.defaultBillable', true));
+ const {getViolationsForField} = useViolations(transactionViolations);
+ const hasViolations = useCallback((field) => canUseViolations && getViolationsForField(field).length > 0, [canUseViolations, getViolationsForField]);
+
let amountDescription = `${translate('iou.amount')}`;
+ const saveBillable = useCallback(
+ (newBillable) => {
+ // If the value hasn't changed, don't request to save changes on the server and just close the modal
+ if (newBillable === TransactionUtils.getBillable(transaction)) {
+ Navigation.dismissModal();
+ return;
+ }
+ IOU.updateMoneyRequestBillable(transaction.transactionID, report.reportID, newBillable);
+ Navigation.dismissModal();
+ },
+ [transaction, report],
+ );
+
if (isCardTransaction) {
if (formattedOriginalAmount) {
amountDescription += ` • ${translate('iou.original')} ${formattedOriginalAmount}`;
@@ -158,12 +217,6 @@ function MoneyRequestView({report, parentReport, parentReportActions, policyCate
}
}
- // A temporary solution to hide the transaction detail
- // This will be removed after we properly add the transaction as a prop
- if (ReportActionsUtils.isDeletedAction(parentReportAction)) {
- return null;
- }
-
const hasReceipt = TransactionUtils.hasReceipt(transaction);
let receiptURIs;
let hasErrors = false;
@@ -188,16 +241,28 @@ function MoneyRequestView({report, parentReport, parentReportActions, policyCate
isLocalFile={receiptURIs.isLocalFile}
transaction={transaction}
enablePreviewModal
+ canEditReceipt={canEditReceipt}
/>
)}
- {!hasReceipt && canEditReceipt && !isSettled && canUseViolations && (
+ {!hasReceipt && canEditReceipt && canUseViolations && (
Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT))}
+ onPress={() =>
+ Navigation.navigate(
+ ROUTES.MONEY_REQUEST_STEP_SCAN.getRoute(
+ CONST.IOU.ACTION.EDIT,
+ CONST.IOU.TYPE.REQUEST,
+ transaction.transactionID,
+ report.reportID,
+ Navigation.getActiveRouteWithoutParams(),
+ ),
+ )
+ }
/>
)}
+ {canUseViolations && }
Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.AMOUNT))}
- brickRoadIndicator={hasErrors && transactionAmount === 0 ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''}
+ brickRoadIndicator={hasViolations('amount') || (hasErrors && transactionAmount === 0) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''}
error={hasErrors && transactionAmount === 0 ? translate('common.error.enterAmount') : ''}
/>
+ {canUseViolations && }
Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.DESCRIPTION))}
wrapperStyle={[styles.pv2, styles.taskDescriptionMenuItem]}
+ brickRoadIndicator={hasViolations('comment') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''}
numberOfLinesTitle={0}
/>
+ {canUseViolations && }
{isDistanceRequest ? (
Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.DISTANCE))}
/>
@@ -241,26 +309,28 @@ function MoneyRequestView({report, parentReport, parentReportActions, policyCate
Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.MERCHANT))}
- brickRoadIndicator={hasErrors && isEmptyMerchant ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''}
+ brickRoadIndicator={hasViolations('merchant') || (hasErrors && isEmptyMerchant) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''}
error={hasErrors && isEmptyMerchant ? translate('common.error.enterMerchant') : ''}
/>
+ {canUseViolations && }
)}
Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.DATE))}
- brickRoadIndicator={hasErrors && transactionDate === '' ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''}
+ brickRoadIndicator={hasViolations('date') || (hasErrors && transactionDate === '') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''}
error={hasErrors && transactionDate === '' ? translate('common.error.enterDate') : ''}
/>
+ {canUseViolations && }
{shouldShowCategory && (
@@ -271,7 +341,9 @@ function MoneyRequestView({report, parentReport, parentReportActions, policyCate
shouldShowRightIcon={canEdit}
titleStyle={styles.flex1}
onPress={() => Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.CATEGORY))}
+ brickRoadIndicator={hasViolations('category') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''}
/>
+ {canUseViolations && }
)}
{shouldShowTag && (
@@ -283,7 +355,9 @@ function MoneyRequestView({report, parentReport, parentReportActions, policyCate
shouldShowRightIcon={canEdit}
titleStyle={styles.flex1}
onPress={() => Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.TAG))}
+ brickRoadIndicator={hasViolations('tag') ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''}
/>
+ {canUseViolations && }
)}
{isCardTransaction && (
@@ -295,15 +369,24 @@ function MoneyRequestView({report, parentReport, parentReportActions, policyCate
/>
)}
+
{shouldShowBillable && (
-
- {translate('common.billable')}
- IOU.editMoneyRequest(transaction, report.reportID, {billable: value})}
- />
-
+ <>
+
+ {translate('common.billable')}
+
+
+ {hasViolations('billable') && (
+
+ )}
+ >
)}
{
+ const parentReportAction = ReportActionsUtils.getParentReportAction(report);
+ const transactionID = lodashGet(parentReportAction, ['originalMessage', 'IOUTransactionID'], 0);
+ return `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`;
+ },
+ },
+ policyTags: {
+ key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report.policyID}`,
+ },
}),
)(MoneyRequestView);
diff --git a/src/components/ReportActionItem/ReportActionItemImage.js b/src/components/ReportActionItem/ReportActionItemImage.js
index 4336a5eddd8a..1495dcbd9111 100644
--- a/src/components/ReportActionItem/ReportActionItemImage.js
+++ b/src/components/ReportActionItem/ReportActionItemImage.js
@@ -31,6 +31,9 @@ const propTypes = {
/** whether thumbnail is refer the local file or not */
isLocalFile: PropTypes.bool,
+
+ /** whether the receipt can be replaced */
+ canEditReceipt: PropTypes.bool,
};
const defaultProps = {
@@ -38,6 +41,7 @@ const defaultProps = {
transaction: {},
enablePreviewModal: false,
isLocalFile: false,
+ canEditReceipt: false,
};
/**
@@ -46,7 +50,7 @@ const defaultProps = {
* and optional preview modal as well.
*/
-function ReportActionItemImage({thumbnail, image, enablePreviewModal, transaction, isLocalFile}) {
+function ReportActionItemImage({thumbnail, image, enablePreviewModal, transaction, canEditReceipt, isLocalFile}) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const imageSource = tryResolveUrlFromApiRoot(image || '');
@@ -88,6 +92,7 @@ function ReportActionItemImage({thumbnail, image, enablePreviewModal, transactio
isAuthTokenRequired={!isLocalFile}
report={report}
isReceiptAttachment
+ canEditReceipt={canEditReceipt}
allowToDownload
originalFileName={transaction.filename}
>
diff --git a/src/components/ReportActionItem/ReportPreview.js b/src/components/ReportActionItem/ReportPreview.js
index e88c057a615d..abc7e3954200 100644
--- a/src/components/ReportActionItem/ReportPreview.js
+++ b/src/components/ReportActionItem/ReportPreview.js
@@ -15,7 +15,6 @@ import {showContextMenuForReport} from '@components/ShowContextMenuContext';
import Text from '@components/Text';
import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import useLocalize from '@hooks/useLocalize';
-import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import compose from '@libs/compose';
@@ -30,7 +29,6 @@ import * as ReportUtils from '@libs/ReportUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import reportActionPropTypes from '@pages/home/report/reportActionPropTypes';
import reportPropTypes from '@pages/reportPropTypes';
-import variables from '@styles/variables';
import * as IOU from '@userActions/IOU';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
@@ -128,7 +126,6 @@ const defaultProps = {
function ReportPreview(props) {
const theme = useTheme();
const styles = useThemeStyles();
- const {getLineHeightStyle} = useStyleUtils();
const {translate} = useLocalize();
const [hasMissingSmartscanFields, sethasMissingSmartscanFields] = useState(false);
@@ -243,10 +240,10 @@ function ReportPreview(props) {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
- const isGroupPolicy = ReportUtils.isGroupPolicyExpenseChat(props.chatReport);
+ const isPaidGroupPolicy = ReportUtils.isPaidGroupPolicyExpenseChat(props.chatReport);
const isPolicyAdmin = policyType !== CONST.POLICY.TYPE.PERSONAL && lodashGet(props.policy, 'role') === CONST.POLICY.ROLE.ADMIN;
- const isPayer = isGroupPolicy
- ? // In a group policy, the admin approver can pay the report directly by skipping the approval step
+ const isPayer = isPaidGroupPolicy
+ ? // In a paid group policy, the admin approver can pay the report directly by skipping the approval step
isPolicyAdmin && (isApproved || isCurrentUserManager)
: isPolicyAdmin || (isMoneyRequestReport && isCurrentUserManager);
const shouldShowPayButton = useMemo(
@@ -254,11 +251,11 @@ function ReportPreview(props) {
[isPayer, isDraftExpenseReport, iouSettled, reimbursableSpend, iouCanceled, props.iouReport],
);
const shouldShowApproveButton = useMemo(() => {
- if (!isGroupPolicy) {
+ if (!isPaidGroupPolicy) {
return false;
}
return isCurrentUserManager && !isDraftExpenseReport && !isApproved && !iouSettled;
- }, [isGroupPolicy, isCurrentUserManager, isDraftExpenseReport, isApproved, iouSettled]);
+ }, [isPaidGroupPolicy, isCurrentUserManager, isDraftExpenseReport, isApproved, iouSettled]);
const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton;
return (
@@ -286,7 +283,7 @@ function ReportPreview(props) {
- {getPreviewMessage()}
+ {getPreviewMessage()}
{!iouSettled && hasErrors && (
;
/** The policy of root parent report */
- rootParentReportpolicy: PropTypes.shape({
- /** The role of current user */
- role: PropTypes.string,
- }),
-
- /** The chat report associated with taskReport */
- chatReportID: PropTypes.string.isRequired,
-
- /** Popover context menu anchor, used for showing context menu */
- contextMenuAnchor: refPropTypes,
-
- /** Callback for updating context menu active state, used for showing context menu */
- checkIfContextMenuActive: PropTypes.func,
-
- /* Onyx Props */
- ...withLocalizePropTypes,
-
- ...withCurrentUserPersonalDetailsPropTypes,
-};
-
-const defaultProps = {
- ...withCurrentUserPersonalDetailsDefaultProps,
- taskReport: {},
- rootParentReportpolicy: {},
- isHovered: false,
+ rootParentReportpolicy: OnyxEntry;
};
-function TaskPreview(props) {
+type TaskPreviewProps = WithCurrentUserPersonalDetailsProps &
+ TaskPreviewOnyxProps & {
+ /** The ID of the associated policy */
+ // eslint-disable-next-line react/no-unused-prop-types
+ policyID: string;
+ /** The ID of the associated taskReport */
+ taskReportID: string;
+
+ /** Whether the task preview is hovered so we can modify its style */
+ isHovered: boolean;
+
+ /** The linked reportAction */
+ action: OnyxEntry;
+
+ /** The chat report associated with taskReport */
+ chatReportID: string;
+
+ /** Popover context menu anchor, used for showing context menu */
+ contextMenuAnchor: Element;
+
+ /** Callback for updating context menu active state, used for showing context menu */
+ checkIfContextMenuActive: () => void;
+ };
+
+function TaskPreview({
+ taskReport,
+ taskReportID,
+ action,
+ contextMenuAnchor,
+ chatReportID,
+ checkIfContextMenuActive,
+ currentUserPersonalDetails,
+ rootParentReportpolicy,
+ isHovered = false,
+}: TaskPreviewProps) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const personalDetails = usePersonalDetails() || CONST.EMPTY_OBJECT;
+ const {translate} = useLocalize();
// The reportAction might not contain details regarding the taskReport
// Only the direct parent reportAction will contain details about the taskReport
// Other linked reportActions will only contain the taskReportID and we will grab the details from there
- const isTaskCompleted = !_.isEmpty(props.taskReport)
- ? props.taskReport.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED && props.taskReport.statusNum === CONST.REPORT.STATUS.APPROVED
- : props.action.childStateNum === CONST.REPORT.STATE_NUM.SUBMITTED && props.action.childStatusNum === CONST.REPORT.STATUS.APPROVED;
- const taskTitle = _.escape(TaskUtils.getTaskTitle(props.taskReportID, props.action.childReportName));
- const taskAssigneeAccountID = Task.getTaskAssigneeAccountID(props.taskReport) || props.action.childManagerAccountID;
- const assigneeLogin = lodashGet(personalDetails, [taskAssigneeAccountID, 'login'], '');
- const assigneeDisplayName = lodashGet(personalDetails, [taskAssigneeAccountID, 'displayName'], '');
+ const isTaskCompleted = !isEmptyObject(taskReport)
+ ? taskReport?.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED && taskReport.statusNum === CONST.REPORT.STATUS.APPROVED
+ : action?.childStateNum === CONST.REPORT.STATE_NUM.SUBMITTED && action?.childStatusNum === CONST.REPORT.STATUS.APPROVED;
+ const taskTitle = Str.htmlEncode(TaskUtils.getTaskTitle(taskReportID, action?.childReportName ?? ''));
+ const taskAssigneeAccountID = Task.getTaskAssigneeAccountID(taskReport ?? {}) ?? action?.childManagerAccountID ?? '';
+ const assigneeLogin = personalDetails[taskAssigneeAccountID]?.login ?? '';
+ const assigneeDisplayName = personalDetails[taskAssigneeAccountID]?.displayName ?? '';
const taskAssignee = assigneeDisplayName || LocalePhoneNumber.formatPhoneNumber(assigneeLogin);
const htmlForTaskPreview =
taskAssignee && taskAssigneeAccountID !== 0
? `@${taskAssignee} ${taskTitle}`
: `${taskTitle}`;
- const isDeletedParentAction = ReportUtils.isCanceledTaskReport(props.taskReport, props.action);
+ const isDeletedParentAction = ReportUtils.isCanceledTaskReport(taskReport, action);
if (isDeletedParentAction) {
- return ${props.translate('parentReportAction.deletedTask')}`} />;
+ return ${translate('parentReportAction.deletedTask')}`} />;
}
return (
Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(props.taskReportID))}
+ onPress={() => Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(taskReportID))}
onPressIn={() => DeviceCapabilities.canUseTouchScreen() && ControlSelection.block()}
onPressOut={() => ControlSelection.unblock()}
- onLongPress={(event) => showContextMenuForReport(event, props.contextMenuAnchor, props.chatReportID, props.action, props.checkIfContextMenuActive)}
+ onLongPress={(event) => showContextMenuForReport(event, contextMenuAnchor, chatReportID, action ?? {}, checkIfContextMenuActive)}
style={[styles.flexRow, styles.justifyContentBetween]}
role={CONST.ROLE.BUTTON}
- accessibilityLabel={props.translate('task.task')}
+ accessibilityLabel={translate('task.task')}
>
{
if (isTaskCompleted) {
- Task.reopenTask(props.taskReport);
+ Task.reopenTask(taskReport ?? {});
} else {
- Task.completeTask(props.taskReport);
+ Task.completeTask(taskReport ?? {});
}
})}
- accessibilityLabel={props.translate('task.task')}
+ accessibilityLabel={translate('task.task')}
/>
);
}
-TaskPreview.propTypes = propTypes;
-TaskPreview.defaultProps = defaultProps;
TaskPreview.displayName = 'TaskPreview';
-export default compose(
- withLocalize,
- withCurrentUserPersonalDetails,
- withOnyx({
+export default withCurrentUserPersonalDetails(
+ withOnyx({
taskReport: {
key: ({taskReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${taskReportID}`,
- initialValue: {},
},
rootParentReportpolicy: {
- key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID || '0'}`,
- selector: (policy) => _.pick(policy, ['role']),
+ key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID ?? '0'}`,
+ selector: (policy: Policy | null) => ({role: policy?.role ?? ''}),
},
- }),
-)(TaskPreview);
+ })(TaskPreview),
+);
diff --git a/src/components/ReportWelcomeText.tsx b/src/components/ReportWelcomeText.tsx
index 248f6894ca37..b337c3581213 100644
--- a/src/components/ReportWelcomeText.tsx
+++ b/src/components/ReportWelcomeText.tsx
@@ -44,6 +44,7 @@ function ReportWelcomeText({report, policy, personalDetails}: ReportWelcomeTextP
const isUserPolicyAdmin = PolicyUtils.isPolicyAdmin(policy);
const roomWelcomeMessage = ReportUtils.getRoomWelcomeMessage(report, isUserPolicyAdmin);
const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, policy, participantAccountIDs);
+ const additionalText = moneyRequestOptions.map((item) => translate(`reportActionsView.iouTypes.${item}`)).join(', ');
const navigateToReport = () => {
if (!report?.reportID) {
@@ -112,7 +113,9 @@ function ReportWelcomeText({report, policy, personalDetails}: ReportWelcomeTextP
))}
)}
- {(moneyRequestOptions.includes(CONST.IOU.TYPE.SEND) || moneyRequestOptions.includes(CONST.IOU.TYPE.REQUEST)) && {translate('reportActionsView.usePlusButton')}}
+ {(moneyRequestOptions.includes(CONST.IOU.TYPE.SEND) || moneyRequestOptions.includes(CONST.IOU.TYPE.REQUEST)) && (
+ {translate('reportActionsView.usePlusButton', {additionalText})}
+ )}
>
);
diff --git a/src/components/RoomNameInput/index.js b/src/components/RoomNameInput/index.js
index 8bfc25a5db75..61f004a47b96 100644
--- a/src/components/RoomNameInput/index.js
+++ b/src/components/RoomNameInput/index.js
@@ -27,18 +27,15 @@ function RoomNameInput({isFocused, autoFocus, disabled, errorText, forwardedRef,
// Prevent cursor jump behaviour:
// Check if newRoomNameWithHash is the same as modifiedRoomName
- // If it is then the room name is valid (does not contain unallowed characters); no action required
- // If not then the room name contains unvalid characters and we must adjust the cursor position manually
+ // If it is, then the room name is valid (does not contain forbidden characters) – no action required
+ // If not, then the room name contains invalid characters, and we must adjust the cursor position manually
// Read more: https://github.com/Expensify/App/issues/12741
const oldRoomNameWithHash = value || '';
const newRoomNameWithHash = `${CONST.POLICY.ROOM_PREFIX}${roomName}`;
if (modifiedRoomName !== newRoomNameWithHash) {
const offset = modifiedRoomName.length - oldRoomNameWithHash.length;
- const newSelection = {
- start: selection.start + offset,
- end: selection.end + offset,
- };
- setSelection(newSelection);
+ const newCursorPosition = selection.end + offset;
+ setSelection({start: newCursorPosition, end: newCursorPosition});
}
};
diff --git a/src/components/Section/IconSection.js b/src/components/Section/IconSection.js
deleted file mode 100644
index 307331aa36d6..000000000000
--- a/src/components/Section/IconSection.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import {View} from 'react-native';
-import Icon from '@components/Icon';
-import sourcePropTypes from '@components/Image/sourcePropTypes';
-import useThemeStyles from '@hooks/useThemeStyles';
-
-const iconSectionPropTypes = {
- icon: sourcePropTypes,
- IconComponent: PropTypes.IconComponent,
- iconContainerStyles: PropTypes.iconContainerStyles,
-};
-
-const defaultIconSectionPropTypes = {
- icon: null,
- IconComponent: null,
- iconContainerStyles: [],
-};
-
-function IconSection({icon, IconComponent, iconContainerStyles}) {
- const styles = useThemeStyles();
-
- return (
-
- {Boolean(icon) && (
-
- )}
- {Boolean(IconComponent) && }
-
- );
-}
-
-IconSection.displayName = 'IconSection';
-IconSection.propTypes = iconSectionPropTypes;
-IconSection.defaultProps = defaultIconSectionPropTypes;
-
-export default IconSection;
diff --git a/src/components/Section/IconSection.tsx b/src/components/Section/IconSection.tsx
new file mode 100644
index 000000000000..cc42c6b7ace5
--- /dev/null
+++ b/src/components/Section/IconSection.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import type {StyleProp, ViewStyle} from 'react-native';
+import {View} from 'react-native';
+import Icon from '@components/Icon';
+import useThemeStyles from '@hooks/useThemeStyles';
+import type IconAsset from '@src/types/utils/IconAsset';
+
+type IconSectionProps = {
+ icon?: IconAsset;
+ iconContainerStyles?: StyleProp;
+};
+
+function IconSection({icon, iconContainerStyles}: IconSectionProps) {
+ const styles = useThemeStyles();
+
+ return (
+
+ {!!icon && (
+
+ )}
+
+ );
+}
+
+IconSection.displayName = 'IconSection';
+
+export default IconSection;
diff --git a/src/components/Section/index.js b/src/components/Section/index.js
deleted file mode 100644
index 50576abef025..000000000000
--- a/src/components/Section/index.js
+++ /dev/null
@@ -1,122 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import {View} from 'react-native';
-import sourcePropTypes from '@components/Image/sourcePropTypes';
-import MenuItemList from '@components/MenuItemList';
-import menuItemPropTypes from '@components/menuItemPropTypes';
-import Text from '@components/Text';
-import useThemeStyles from '@hooks/useThemeStyles';
-import IconSection from './IconSection';
-
-const CARD_LAYOUT = {
- ICON_ON_TOP: 'iconOnTop',
- ICON_ON_RIGHT: 'iconOnRight',
-};
-
-const propTypes = {
- /** An array of props that are pass to individual MenuItem components */
- menuItems: PropTypes.arrayOf(PropTypes.shape(menuItemPropTypes)),
-
- /** The text to display in the title of the section */
- title: PropTypes.string.isRequired,
-
- /** The text to display in the subtitle of the section */
- subtitle: PropTypes.string,
-
- /** The icon to display along with the title */
- icon: sourcePropTypes,
-
- /** Icon component */
- IconComponent: PropTypes.func,
-
- /** Card layout that affects icon positioning, margins, sizes. */
- // eslint-disable-next-line rulesdir/prefer-underscore-method
- cardLayout: PropTypes.oneOf(Object.values(CARD_LAYOUT)),
-
- /** Contents to display inside the section */
- children: PropTypes.node,
-
- /** Customize the Section container */
- // eslint-disable-next-line react/forbid-prop-types
- containerStyles: PropTypes.arrayOf(PropTypes.object),
-
- /** Customize the Section container */
- // eslint-disable-next-line react/forbid-prop-types
- titleStyles: PropTypes.arrayOf(PropTypes.object),
-
- /** Customize the Section container */
- // eslint-disable-next-line react/forbid-prop-types
- subtitleStyles: PropTypes.arrayOf(PropTypes.object),
-
- /** Whether the subtitle should have a muted style */
- subtitleMuted: PropTypes.bool,
-
- /** Customize the Section container */
- // eslint-disable-next-line react/forbid-prop-types
- childrenStyles: PropTypes.arrayOf(PropTypes.object),
-
- /** Customize the Icon container */
- // eslint-disable-next-line react/forbid-prop-types
- iconContainerStyles: PropTypes.arrayOf(PropTypes.object),
-};
-
-const defaultProps = {
- menuItems: null,
- children: null,
- icon: null,
- IconComponent: null,
- cardLayout: CARD_LAYOUT.ICON_ON_RIGHT,
- containerStyles: [],
- iconContainerStyles: [],
- titleStyles: [],
- subtitleStyles: [],
- subtitleMuted: false,
- childrenStyles: [],
- subtitle: null,
-};
-
-function Section({children, childrenStyles, containerStyles, icon, IconComponent, cardLayout, iconContainerStyles, menuItems, subtitle, subtitleStyles, subtitleMuted, title, titleStyles}) {
- const styles = useThemeStyles();
-
- return (
- <>
-
- {cardLayout === CARD_LAYOUT.ICON_ON_TOP && (
-
- )}
-
-
- {title}
-
- {cardLayout === CARD_LAYOUT.ICON_ON_RIGHT && (
-
- )}
-
-
- {Boolean(subtitle) && (
-
- {subtitle}
-
- )}
-
- {children}
-
- {Boolean(menuItems) && }
-
- >
- );
-}
-Section.displayName = 'Section';
-Section.propTypes = propTypes;
-Section.defaultProps = defaultProps;
-
-export {CARD_LAYOUT};
-export default Section;
diff --git a/src/components/Section/index.tsx b/src/components/Section/index.tsx
new file mode 100644
index 000000000000..f24316a5f1bb
--- /dev/null
+++ b/src/components/Section/index.tsx
@@ -0,0 +1,106 @@
+import React from 'react';
+import type {StyleProp, ViewStyle} from 'react-native';
+import {View} from 'react-native';
+import type {ValueOf} from 'type-fest';
+import type {MenuItemWithLink} from '@components/MenuItemList';
+import MenuItemList from '@components/MenuItemList';
+import Text from '@components/Text';
+import useThemeStyles from '@hooks/useThemeStyles';
+import type ChildrenProps from '@src/types/utils/ChildrenProps';
+import type IconAsset from '@src/types/utils/IconAsset';
+import IconSection from './IconSection';
+
+const CARD_LAYOUT = {
+ ICON_ON_TOP: 'iconOnTop',
+ ICON_ON_RIGHT: 'iconOnRight',
+} as const;
+
+type SectionProps = ChildrenProps & {
+ /** An array of props that are passed to individual MenuItem components */
+ menuItems?: MenuItemWithLink[];
+
+ /** The text to display in the title of the section */
+ title: string;
+
+ /** The text to display in the subtitle of the section */
+ subtitle?: string;
+
+ /** The icon to display along with the title */
+ icon?: IconAsset;
+
+ /** Card layout that affects icon positioning, margins, sizes */
+ cardLayout?: ValueOf;
+
+ /** Whether the subtitle should have a muted style */
+ subtitleMuted?: boolean;
+
+ /** Customize the Section container */
+ containerStyles?: StyleProp;
+
+ /** Customize the Section container */
+ titleStyles?: StyleProp;
+
+ /** Customize the Section container */
+ subtitleStyles?: StyleProp;
+
+ /** Customize the Section container */
+ childrenStyles?: StyleProp;
+
+ /** Customize the Icon container */
+ iconContainerStyles?: StyleProp;
+};
+
+function Section({
+ children,
+ childrenStyles,
+ containerStyles,
+ icon,
+ cardLayout = CARD_LAYOUT.ICON_ON_RIGHT,
+ iconContainerStyles,
+ menuItems,
+ subtitle,
+ subtitleStyles,
+ subtitleMuted = false,
+ title,
+ titleStyles,
+}: SectionProps) {
+ const styles = useThemeStyles();
+
+ return (
+ <>
+
+ {cardLayout === CARD_LAYOUT.ICON_ON_TOP && (
+
+ )}
+
+
+ {title}
+
+ {cardLayout === CARD_LAYOUT.ICON_ON_RIGHT && (
+
+ )}
+
+
+ {!!subtitle && (
+
+ {subtitle}
+
+ )}
+
+ {children}
+
+ {!!menuItems && }
+
+ >
+ );
+}
+Section.displayName = 'Section';
+
+export {CARD_LAYOUT};
+export default Section;
diff --git a/src/components/SelectionList/BaseListItem.js b/src/components/SelectionList/BaseListItem.js
index 443b930d5e7a..cfd39ab0ebb8 100644
--- a/src/components/SelectionList/BaseListItem.js
+++ b/src/components/SelectionList/BaseListItem.js
@@ -24,6 +24,7 @@ function BaseListItem({
canSelectMultiple = false,
onSelectRow,
onDismissError = () => {},
+ rightHandSideComponent,
keyForList,
}) {
const theme = useTheme();
@@ -33,6 +34,18 @@ function BaseListItem({
const isUserItem = lodashGet(item, 'icons.length', 0) > 0;
const ListItem = isUserItem ? UserListItem : RadioListItem;
+ const rightHandSideComponentRender = () => {
+ if (canSelectMultiple || !rightHandSideComponent) {
+ return null;
+ }
+
+ if (typeof rightHandSideComponent === 'function') {
+ return rightHandSideComponent(item);
+ }
+
+ return rightHandSideComponent;
+ };
+
return (
onDismissError(item)}
@@ -62,7 +75,10 @@ function BaseListItem({
]}
>
{canSelectMultiple && (
-
+
- {!canSelectMultiple && item.isSelected && (
+ {!canSelectMultiple && item.isSelected && !rightHandSideComponent && (
)}
+ {rightHandSideComponentRender()}
{Boolean(item.invitedSecondaryLogin) && (
diff --git a/src/components/SelectionList/BaseSelectionList.js b/src/components/SelectionList/BaseSelectionList.js
index 213c55e8d8b9..960618808fd9 100644
--- a/src/components/SelectionList/BaseSelectionList.js
+++ b/src/components/SelectionList/BaseSelectionList.js
@@ -14,7 +14,7 @@ import SectionList from '@components/SectionList';
import Text from '@components/Text';
import TextInput from '@components/TextInput';
import withKeyboardState, {keyboardStatePropTypes} from '@components/withKeyboardState';
-import useActiveElement from '@hooks/useActiveElement';
+import useActiveElementRole from '@hooks/useActiveElementRole';
import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
import useLocalize from '@hooks/useLocalize';
import useStyleUtils from '@hooks/useStyleUtils';
@@ -40,6 +40,7 @@ function BaseSelectionList({
textInputLabel = '',
textInputPlaceholder = '',
textInputValue = '',
+ textInputHint = '',
textInputMaxLength,
inputMode = CONST.INPUT_MODE.TEXT,
onChangeText,
@@ -62,7 +63,9 @@ function BaseSelectionList({
disableKeyboardShortcuts = false,
children,
shouldStopPropagation = false,
+ shouldShowTooltips = true,
shouldUseDynamicMaxToRenderPerBatch = false,
+ rightHandSideComponent,
}) {
const theme = useTheme();
const styles = useThemeStyles();
@@ -73,11 +76,10 @@ function BaseSelectionList({
const focusTimeoutRef = useRef(null);
const shouldShowTextInput = Boolean(textInputLabel);
const shouldShowSelectAll = Boolean(onSelectAll);
- const activeElement = useActiveElement();
+ const activeElementRole = useActiveElementRole();
const isFocused = useIsFocused();
const [maxToRenderPerBatch, setMaxToRenderPerBatch] = useState(shouldUseDynamicMaxToRenderPerBatch ? 0 : CONST.MAX_TO_RENDER_PER_BATCH.DEFAULT);
- const [isInitialRender, setIsInitialRender] = useState(true);
- const wrapperStyles = useMemo(() => ({opacity: isInitialRender ? 0 : 1}), [isInitialRender]);
+ const [isInitialSectionListRender, setIsInitialSectionListRender] = useState(true);
/**
* Iterates through the sections and items inside each section, and builds 3 arrays along the way:
@@ -156,7 +158,7 @@ function BaseSelectionList({
const [focusedIndex, setFocusedIndex] = useState(() => _.findIndex(flattenedSections.allOptions, (option) => option.keyForList === initiallyFocusedOptionKey));
// Disable `Enter` shortcut if the active element is a button or checkbox
- const disableEnterShortcut = activeElement && [CONST.ROLE.BUTTON, CONST.ROLE.CHECKBOX].includes(activeElement.role);
+ const disableEnterShortcut = activeElementRole && [CONST.ROLE.BUTTON, CONST.ROLE.CHECKBOX].includes(activeElementRole);
/**
* Scrolls to the desired item index in the section list
@@ -303,7 +305,7 @@ function BaseSelectionList({
const isDisabled = section.isDisabled || item.isDisabled;
const isItemFocused = !isDisabled && focusedIndex === normalizedIndex;
// We only create tooltips for the first 10 users or so since some reports have hundreds of users, causing performance to degrade.
- const showTooltip = normalizedIndex < 10;
+ const showTooltip = shouldShowTooltips && normalizedIndex < 10;
return (
);
@@ -331,13 +334,13 @@ function BaseSelectionList({
setMaxToRenderPerBatch((Math.ceil(listHeight / itemHeight) || 0) + CONST.MAX_TO_RENDER_PER_BATCH.DEFAULT);
}
- if (!isInitialRender) {
+ if (!isInitialSectionListRender) {
return;
}
scrollToIndex(focusedIndex, false);
- setIsInitialRender(false);
+ setIsInitialSectionListRender(false);
},
- [focusedIndex, isInitialRender, scrollToIndex, shouldUseDynamicMaxToRenderPerBatch],
+ [focusedIndex, isInitialSectionListRender, scrollToIndex, shouldUseDynamicMaxToRenderPerBatch],
);
const updateAndScrollToFocusedIndex = useCallback(
@@ -365,7 +368,7 @@ function BaseSelectionList({
useEffect(() => {
// do not change focus on the first render, as it should focus on the selected item
- if (isInitialRender) {
+ if (isInitialSectionListRender) {
return;
}
@@ -401,7 +404,7 @@ function BaseSelectionList({
{/* */}
{({safeAreaPaddingBottomStyle}) => (
-
+
{shouldShowTextInput && (
{children}
>
diff --git a/src/components/SelectionList/UserListItem.js b/src/components/SelectionList/UserListItem.js
index 39b7e02df3eb..a842f19858f2 100644
--- a/src/components/SelectionList/UserListItem.js
+++ b/src/components/SelectionList/UserListItem.js
@@ -4,11 +4,13 @@ import {View} from 'react-native';
import SubscriptAvatar from '@components/SubscriptAvatar';
import Text from '@components/Text';
import Tooltip from '@components/Tooltip';
+import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import {userListItemPropTypes} from './selectionListPropTypes';
-function UserListItem({item, textStyles, alternateTextStyles, showTooltip}) {
+function UserListItem({item, textStyles, alternateTextStyles, showTooltip, style}) {
const styles = useThemeStyles();
+ const StyleUtils = useStyleUtils();
return (
<>
{Boolean(item.icons) && (
@@ -24,7 +26,7 @@ function UserListItem({item, textStyles, alternateTextStyles, showTooltip}) {
text={item.text}
>
{item.text}
@@ -36,7 +38,7 @@ function UserListItem({item, textStyles, alternateTextStyles, showTooltip}) {
text={item.alternateText}
>
{item.alternateText}
diff --git a/src/components/SelectionList/selectionListPropTypes.js b/src/components/SelectionList/selectionListPropTypes.js
index b753607cda61..f5178112a4c3 100644
--- a/src/components/SelectionList/selectionListPropTypes.js
+++ b/src/components/SelectionList/selectionListPropTypes.js
@@ -22,7 +22,7 @@ const commonListItemPropTypes = {
/** Whether to use the Checkbox (multiple selection) instead of the Checkmark (single selection) */
canSelectMultiple: PropTypes.bool,
- /** Callback to fire when the item is pressed */
+ /** Callback to fire when the item is selected */
onSelectRow: PropTypes.func.isRequired,
/** Callback to fire when an error is dismissed */
@@ -190,8 +190,14 @@ const propTypes = {
/** Custom content to display in the footer */
footerContent: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
+ /** Whether to show the toolip text */
+ shouldShowTooltips: PropTypes.bool,
+
/** Whether to use dynamic maxToRenderPerBatch depending on the visible number of elements */
shouldUseDynamicMaxToRenderPerBatch: PropTypes.bool,
+
+ /** Right hand side component to display in the list item. Function has list item passed as the param */
+ rightHandSideComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
};
export {propTypes, baseListItemPropTypes, radioListItemPropTypes, userListItemPropTypes};
diff --git a/src/components/SignInButtons/AppleAuthWrapper/index.ios.js b/src/components/SignInButtons/AppleAuthWrapper/index.ios.tsx
similarity index 81%
rename from src/components/SignInButtons/AppleAuthWrapper/index.ios.js
rename to src/components/SignInButtons/AppleAuthWrapper/index.ios.tsx
index 69882d89b1fe..12ead0267db3 100644
--- a/src/components/SignInButtons/AppleAuthWrapper/index.ios.js
+++ b/src/components/SignInButtons/AppleAuthWrapper/index.ios.tsx
@@ -5,19 +5,18 @@ import * as Session from '@userActions/Session';
/**
* Apple Sign In wrapper for iOS
* revokes the session if the credential is revoked.
- *
- * @returns {null}
*/
function AppleAuthWrapper() {
useEffect(() => {
if (!appleAuth.isSupported) {
return;
}
- const listener = appleAuth.onCredentialRevoked(() => {
+ const removeListener = appleAuth.onCredentialRevoked(() => {
Session.signOut();
});
+
return () => {
- listener.remove();
+ removeListener();
};
}, []);
diff --git a/src/components/SignInButtons/AppleAuthWrapper/index.js b/src/components/SignInButtons/AppleAuthWrapper/index.tsx
similarity index 100%
rename from src/components/SignInButtons/AppleAuthWrapper/index.js
rename to src/components/SignInButtons/AppleAuthWrapper/index.tsx
diff --git a/src/components/SignInButtons/AppleSignIn/index.android.js b/src/components/SignInButtons/AppleSignIn/index.android.tsx
similarity index 92%
rename from src/components/SignInButtons/AppleSignIn/index.android.js
rename to src/components/SignInButtons/AppleSignIn/index.android.tsx
index 9dc736789c61..cfd1c48ee8b5 100644
--- a/src/components/SignInButtons/AppleSignIn/index.android.js
+++ b/src/components/SignInButtons/AppleSignIn/index.android.tsx
@@ -18,9 +18,9 @@ const config = {
/**
* Apple Sign In method for Android that returns authToken.
- * @returns {Promise}
+ * @returns Promise that returns a string when resolved
*/
-function appleSignInRequest() {
+function appleSignInRequest(): Promise {
appleAuthAndroid.configure(config);
return appleAuthAndroid
.signIn()
@@ -32,7 +32,6 @@ function appleSignInRequest() {
/**
* Apple Sign In button for Android.
- * @returns {React.Component}
*/
function AppleSignIn() {
const handleSignIn = () => {
diff --git a/src/components/SignInButtons/AppleSignIn/index.desktop.js b/src/components/SignInButtons/AppleSignIn/index.desktop.tsx
similarity index 96%
rename from src/components/SignInButtons/AppleSignIn/index.desktop.js
rename to src/components/SignInButtons/AppleSignIn/index.desktop.tsx
index cc7ae5b623a5..792c16ed0b4a 100644
--- a/src/components/SignInButtons/AppleSignIn/index.desktop.js
+++ b/src/components/SignInButtons/AppleSignIn/index.desktop.tsx
@@ -10,7 +10,6 @@ const appleSignInWebRouteForDesktopFlow = `${CONFIG.EXPENSIFY.NEW_EXPENSIFY_URL}
/**
* Apple Sign In button for desktop flow
- * @returns {React.Component}
*/
function AppleSignIn() {
const styles = useThemeStyles();
diff --git a/src/components/SignInButtons/AppleSignIn/index.ios.js b/src/components/SignInButtons/AppleSignIn/index.ios.tsx
similarity index 91%
rename from src/components/SignInButtons/AppleSignIn/index.ios.js
rename to src/components/SignInButtons/AppleSignIn/index.ios.tsx
index f5c6333dcf7b..3fb1179d0365 100644
--- a/src/components/SignInButtons/AppleSignIn/index.ios.js
+++ b/src/components/SignInButtons/AppleSignIn/index.ios.tsx
@@ -7,9 +7,9 @@ import CONST from '@src/CONST';
/**
* Apple Sign In method for iOS that returns identityToken.
- * @returns {Promise}
+ * @returns Promise that returns a string when resolved
*/
-function appleSignInRequest() {
+function appleSignInRequest(): Promise {
return appleAuth
.performRequest({
requestedOperation: appleAuth.Operation.LOGIN,
@@ -20,7 +20,7 @@ function appleSignInRequest() {
.then((response) =>
appleAuth.getCredentialStateForUser(response.user).then((credentialState) => {
if (credentialState !== appleAuth.State.AUTHORIZED) {
- Log.alert('[Apple Sign In] Authentication failed. Original response: ', response);
+ Log.alert('[Apple Sign In] Authentication failed. Original response: ', {response});
throw new Error('Authentication failed');
}
return response.identityToken;
@@ -30,7 +30,6 @@ function appleSignInRequest() {
/**
* Apple Sign In button for iOS.
- * @returns {React.Component}
*/
function AppleSignIn() {
const handleSignIn = () => {
diff --git a/src/components/SignInButtons/AppleSignIn/index.website.js b/src/components/SignInButtons/AppleSignIn/index.website.tsx
similarity index 75%
rename from src/components/SignInButtons/AppleSignIn/index.website.js
rename to src/components/SignInButtons/AppleSignIn/index.website.tsx
index adae0a691e13..9d7322878c98 100644
--- a/src/components/SignInButtons/AppleSignIn/index.website.js
+++ b/src/components/SignInButtons/AppleSignIn/index.website.tsx
@@ -1,45 +1,39 @@
-import get from 'lodash/get';
-import PropTypes from 'prop-types';
import React, {useEffect, useState} from 'react';
+import type {NativeConfig} from 'react-native-config';
import Config from 'react-native-config';
import getUserLanguage from '@components/SignInButtons/GetUserLanguage';
+import type {WithNavigationFocusProps} from '@components/withNavigationFocus';
import withNavigationFocus from '@components/withNavigationFocus';
import Log from '@libs/Log';
import * as Session from '@userActions/Session';
import CONFIG from '@src/CONFIG';
import CONST from '@src/CONST';
+import type {AppleIDSignInOnFailureEvent, AppleIDSignInOnSuccessEvent} from '@src/types/modules/dom';
// react-native-config doesn't trim whitespace on iOS for some reason so we
// add a trim() call to lodashGet here to prevent headaches.
-const lodashGet = (config, key, defaultValue) => get(config, key, defaultValue).trim();
+const getConfig = (config: NativeConfig, key: string, defaultValue: string) => (config?.[key] ?? defaultValue).trim();
-const requiredPropTypes = {
- isDesktopFlow: PropTypes.bool.isRequired,
+type AppleSignInDivProps = {
+ isDesktopFlow: boolean;
};
-const singletonPropTypes = {
- ...requiredPropTypes,
-
- // From withNavigationFocus
- isFocused: PropTypes.bool.isRequired,
+type SingletonAppleSignInButtonProps = AppleSignInDivProps & {
+ isFocused: boolean;
};
-const propTypes = {
- // Prop to indicate if this is the desktop flow or not.
- isDesktopFlow: PropTypes.bool,
-};
-const defaultProps = {
- isDesktopFlow: false,
+type AppleSignInProps = WithNavigationFocusProps & {
+ isDesktopFlow?: boolean;
};
/**
* Apple Sign In Configuration for Web.
*/
const config = {
- clientId: lodashGet(Config, 'ASI_CLIENTID_OVERRIDE', CONFIG.APPLE_SIGN_IN.SERVICE_ID),
+ clientId: getConfig(Config, 'ASI_CLIENTID_OVERRIDE', CONFIG.APPLE_SIGN_IN.SERVICE_ID),
scope: 'name email',
// never used, but required for configuration
- redirectURI: lodashGet(Config, 'ASI_REDIRECTURI_OVERRIDE', CONFIG.APPLE_SIGN_IN.REDIRECT_URI),
+ redirectURI: getConfig(Config, 'ASI_REDIRECTURI_OVERRIDE', CONFIG.APPLE_SIGN_IN.REDIRECT_URI),
state: '',
nonce: '',
usePopup: true,
@@ -49,23 +43,22 @@ const config = {
* Apple Sign In success and failure listeners.
*/
-const successListener = (event) => {
+const successListener = (event: AppleIDSignInOnSuccessEvent) => {
const token = event.detail.authorization.id_token;
Session.beginAppleSignIn(token);
};
-const failureListener = (event) => {
+const failureListener = (event: AppleIDSignInOnFailureEvent) => {
if (!event.detail || event.detail.error === 'popup_closed_by_user') {
return null;
}
- Log.warn(`Apple sign-in failed: ${event.detail}`);
+ Log.warn(`Apple sign-in failed: ${event.detail.error}`);
};
/**
* Apple Sign In button for Web.
- * @returns {React.Component}
*/
-function AppleSignInDiv({isDesktopFlow}) {
+function AppleSignInDiv({isDesktopFlow}: AppleSignInDivProps) {
useEffect(() => {
// `init` renders the button, so it must be called after the div is
// first mounted.
@@ -108,24 +101,20 @@ function AppleSignInDiv({isDesktopFlow}) {
);
}
-AppleSignInDiv.propTypes = requiredPropTypes;
-
// The Sign in with Apple script may fail to render button if there are multiple
// of these divs present in the app, as it matches based on div id. So we'll
// only mount the div when it should be visible.
-function SingletonAppleSignInButton({isFocused, isDesktopFlow}) {
+function SingletonAppleSignInButton({isFocused, isDesktopFlow}: SingletonAppleSignInButtonProps) {
if (!isFocused) {
return null;
}
return ;
}
-SingletonAppleSignInButton.propTypes = singletonPropTypes;
-
// withNavigationFocus is used to only render the button when it is visible.
const SingletonAppleSignInButtonWithFocus = withNavigationFocus(SingletonAppleSignInButton);
-function AppleSignIn({isDesktopFlow}) {
+function AppleSignIn({isDesktopFlow = false}: AppleSignInProps) {
const [scriptLoaded, setScriptLoaded] = useState(false);
useEffect(() => {
if (window.appleAuthScriptLoaded) {
@@ -148,7 +137,5 @@ function AppleSignIn({isDesktopFlow}) {
return ;
}
-AppleSignIn.propTypes = propTypes;
-AppleSignIn.defaultProps = defaultProps;
-
+AppleSignIn.displayName = 'AppleSignIn';
export default withNavigationFocus(AppleSignIn);
diff --git a/src/components/SignInButtons/GetUserLanguage.js b/src/components/SignInButtons/GetUserLanguage.ts
similarity index 50%
rename from src/components/SignInButtons/GetUserLanguage.js
rename to src/components/SignInButtons/GetUserLanguage.ts
index 7f45f1fa1e89..a1101e92f656 100644
--- a/src/components/SignInButtons/GetUserLanguage.js
+++ b/src/components/SignInButtons/GetUserLanguage.ts
@@ -1,11 +1,16 @@
+import type {ValueOf} from 'type-fest';
+
const localeCodes = {
en: 'en_US',
es: 'es_ES',
-};
+} as const;
+
+type LanguageCode = keyof typeof localeCodes;
+type LocaleCode = ValueOf;
-const GetUserLanguage = () => {
+const GetUserLanguage = (): LocaleCode => {
const userLanguage = navigator.language || navigator.userLanguage;
- const languageCode = userLanguage.split('-')[0];
+ const languageCode = userLanguage.split('-')[0] as LanguageCode;
return localeCodes[languageCode] || 'en_US';
};
diff --git a/src/components/SignInButtons/GoogleSignIn/index.desktop.js b/src/components/SignInButtons/GoogleSignIn/index.desktop.tsx
similarity index 78%
rename from src/components/SignInButtons/GoogleSignIn/index.desktop.js
rename to src/components/SignInButtons/GoogleSignIn/index.desktop.tsx
index 9284a5332e3d..3c2abb1679f0 100644
--- a/src/components/SignInButtons/GoogleSignIn/index.desktop.js
+++ b/src/components/SignInButtons/GoogleSignIn/index.desktop.tsx
@@ -1,19 +1,15 @@
import React from 'react';
import {View} from 'react-native';
import IconButton from '@components/SignInButtons/IconButton';
-import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import CONFIG from '@src/CONFIG';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';
-const propTypes = {...withLocalizePropTypes};
-
const googleSignInWebRouteForDesktopFlow = `${CONFIG.EXPENSIFY.NEW_EXPENSIFY_URL}${ROUTES.GOOGLE_SIGN_IN}`;
/**
* Google Sign In button for desktop flow.
- * @returns {React.Component}
*/
function GoogleSignIn() {
const styles = useThemeStyles();
@@ -30,6 +26,5 @@ function GoogleSignIn() {
}
GoogleSignIn.displayName = 'GoogleSignIn';
-GoogleSignIn.propTypes = propTypes;
-export default withLocalize(GoogleSignIn);
+export default GoogleSignIn;
diff --git a/src/components/SignInButtons/GoogleSignIn/index.native.js b/src/components/SignInButtons/GoogleSignIn/index.native.tsx
similarity index 98%
rename from src/components/SignInButtons/GoogleSignIn/index.native.js
rename to src/components/SignInButtons/GoogleSignIn/index.native.tsx
index c7ac763cfb73..2744d8958080 100644
--- a/src/components/SignInButtons/GoogleSignIn/index.native.js
+++ b/src/components/SignInButtons/GoogleSignIn/index.native.tsx
@@ -43,7 +43,6 @@ function googleSignInRequest() {
/**
* Google Sign In button for iOS.
- * @returns {React.Component}
*/
function GoogleSignIn() {
return (
diff --git a/src/components/SignInButtons/GoogleSignIn/index.website.js b/src/components/SignInButtons/GoogleSignIn/index.website.tsx
similarity index 83%
rename from src/components/SignInButtons/GoogleSignIn/index.website.js
rename to src/components/SignInButtons/GoogleSignIn/index.website.tsx
index 8f8a977bdb09..3cc4cdebffa6 100644
--- a/src/components/SignInButtons/GoogleSignIn/index.website.js
+++ b/src/components/SignInButtons/GoogleSignIn/index.website.tsx
@@ -1,28 +1,21 @@
-import PropTypes from 'prop-types';
import React, {useCallback} from 'react';
import {View} from 'react-native';
-import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import * as Session from '@userActions/Session';
import CONFIG from '@src/CONFIG';
import CONST from '@src/CONST';
+import type Response from '@src/types/modules/google';
-const propTypes = {
- /** Whether we're rendering in the Desktop Flow, if so show a different button. */
- isDesktopFlow: PropTypes.bool,
-
- ...withLocalizePropTypes,
-};
-
-const defaultProps = {
- isDesktopFlow: false,
+type GoogleSignInProps = {
+ isDesktopFlow?: boolean;
};
/** Div IDs for styling the two different Google Sign-In buttons. */
const mainId = 'google-sign-in-main';
const desktopId = 'google-sign-in-desktop';
-const signIn = (response) => {
+const signIn = (response: Response) => {
Session.beginGoogleSignIn(response.credential);
};
@@ -31,12 +24,15 @@ const signIn = (response) => {
* We have to load the gis script and then determine if the page is focused before rendering the button.
* @returns {React.Component}
*/
-function GoogleSignIn({translate, isDesktopFlow}) {
+
+function GoogleSignIn({isDesktopFlow = false}: GoogleSignInProps) {
+ const {translate} = useLocalize();
const styles = useThemeStyles();
const loadScript = useCallback(() => {
const google = window.google;
if (google) {
google.accounts.id.initialize({
+ // eslint-disable-next-line @typescript-eslint/naming-convention
client_id: CONFIG.GOOGLE_SIGN_IN.WEB_CLIENT_ID,
callback: signIn,
});
@@ -92,7 +88,5 @@ function GoogleSignIn({translate, isDesktopFlow}) {
}
GoogleSignIn.displayName = 'GoogleSignIn';
-GoogleSignIn.propTypes = propTypes;
-GoogleSignIn.defaultProps = defaultProps;
-export default withLocalize(GoogleSignIn);
+export default GoogleSignIn;
diff --git a/src/components/SignInButtons/IconButton.js b/src/components/SignInButtons/IconButton.tsx
similarity index 65%
rename from src/components/SignInButtons/IconButton.js
rename to src/components/SignInButtons/IconButton.tsx
index 19a5bd9b27b8..7ef476cff18a 100644
--- a/src/components/SignInButtons/IconButton.js
+++ b/src/components/SignInButtons/IconButton.tsx
@@ -1,25 +1,13 @@
-import PropTypes from 'prop-types';
import React from 'react';
+import type {ValueOf} from 'type-fest';
import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';
import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
-import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import CONST from '@src/CONST';
-
-const propTypes = {
- /** The on press method */
- onPress: PropTypes.func,
-
- /** Which provider you are using to sign in */
- provider: PropTypes.string.isRequired,
-
- ...withLocalizePropTypes,
-};
-
-const defaultProps = {
- onPress: () => {},
-};
+import type {TranslationPaths} from '@src/languages/types';
+import type IconAsset from '@src/types/utils/IconAsset';
const providerData = {
[CONST.SIGN_IN_METHOD.APPLE]: {
@@ -30,9 +18,21 @@ const providerData = {
icon: Expensicons.GoogleLogo,
accessibilityLabel: 'common.signInWithGoogle',
},
+} satisfies Record<
+ ValueOf,
+ {
+ icon: IconAsset;
+ accessibilityLabel: TranslationPaths;
+ }
+>;
+
+type IconButtonProps = {
+ onPress?: () => void;
+ provider: ValueOf;
};
-function IconButton({onPress, translate, provider}) {
+function IconButton({onPress = () => {}, provider}: IconButtonProps) {
+ const {translate} = useLocalize();
const styles = useThemeStyles();
return (
{},
label: undefined,
+ onBlur: () => {},
};
-function StatePicker({value, errorText, onInputChange, forwardedRef, label}) {
+function StatePicker({value, errorText, onInputChange, forwardedRef, label, onBlur}) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const [isPickerVisible, setIsPickerVisible] = useState(false);
@@ -45,7 +49,10 @@ function StatePicker({value, errorText, onInputChange, forwardedRef, label}) {
setIsPickerVisible(true);
};
- const hidePickerModal = () => {
+ const hidePickerModal = (shouldBlur = true) => {
+ if (shouldBlur) {
+ onBlur();
+ }
setIsPickerVisible(false);
};
@@ -53,7 +60,9 @@ function StatePicker({value, errorText, onInputChange, forwardedRef, label}) {
if (state.value !== value) {
onInputChange(state.value);
}
- hidePickerModal();
+ // If the user selects any state, call the hidePickerModal function with shouldBlur = false
+ // to prevent the onBlur function from being called.
+ hidePickerModal(false);
};
const title = value && _.keys(COMMON_CONST.STATES).includes(value) ? translate(`allStates.${value}.stateName`) : '';
diff --git a/src/components/TabSelector/TabLabel.tsx b/src/components/TabSelector/TabLabel.tsx
index 40f4dc30bb97..548b4ebccbc8 100644
--- a/src/components/TabSelector/TabLabel.tsx
+++ b/src/components/TabSelector/TabLabel.tsx
@@ -1,5 +1,6 @@
import React from 'react';
-import {Animated, StyleSheet, Text, View} from 'react-native';
+import {Animated, StyleSheet, View} from 'react-native';
+import Text from '@components/Text';
import useThemeStyles from '@hooks/useThemeStyles';
type TabLabelProps = {
diff --git a/src/components/Text.tsx b/src/components/Text.tsx
index f8f8a90168fa..f436b9f4495a 100644
--- a/src/components/Text.tsx
+++ b/src/components/Text.tsx
@@ -3,7 +3,8 @@ import React from 'react';
import {Text as RNText, StyleSheet} from 'react-native';
import type {TextProps as RNTextProps, TextStyle} from 'react-native';
import useTheme from '@hooks/useTheme';
-import fontFamily from '@styles/utils/fontFamily';
+import type {FontUtilsType} from '@styles/utils/FontUtils';
+import FontUtils from '@styles/utils/FontUtils';
import variables from '@styles/variables';
import type ChildrenProps from '@src/types/utils/ChildrenProps';
@@ -22,7 +23,7 @@ type TextProps = RNTextProps &
children: React.ReactNode;
/** The family of the font to use */
- family?: keyof typeof fontFamily;
+ family?: keyof FontUtilsType['fontFamily']['platform'];
};
function Text({color, fontSize = variables.fontSizeNormal, textAlign = 'left', children, family = 'EXP_NEUE', style = {}, ...props}: TextProps, ref: ForwardedRef) {
@@ -32,7 +33,7 @@ function Text({color, fontSize = variables.fontSizeNormal, textAlign = 'left', c
color: color ?? theme.text,
fontSize,
textAlign,
- fontFamily: fontFamily[family],
+ fontFamily: FontUtils.fontFamily.platform[family],
...StyleSheet.flatten(style),
};
diff --git a/src/components/TextInput/BaseTextInput/baseTextInputPropTypes.js b/src/components/TextInput/BaseTextInput/baseTextInputPropTypes.js
index 78c37e94196a..78f06b4075e0 100644
--- a/src/components/TextInput/BaseTextInput/baseTextInputPropTypes.js
+++ b/src/components/TextInput/BaseTextInput/baseTextInputPropTypes.js
@@ -26,6 +26,9 @@ const propTypes = {
/** Customize the TextInput container */
textInputContainerStyles: PropTypes.arrayOf(PropTypes.object),
+ /** Customizes the touchable wrapper of the TextInput component */
+ touchableInputWrapperStyle: PropTypes.arrayOf(PropTypes.object),
+
/** Customize the main container */
containerStyles: PropTypes.arrayOf(PropTypes.object),
diff --git a/src/components/TextInput/BaseTextInput/index.native.tsx b/src/components/TextInput/BaseTextInput/index.native.tsx
index f4cc1ee9e0ba..d19d835d68bb 100644
--- a/src/components/TextInput/BaseTextInput/index.native.tsx
+++ b/src/components/TextInput/BaseTextInput/index.native.tsx
@@ -37,6 +37,7 @@ function BaseTextInput(
errorText = '',
icon = null,
textInputContainerStyles,
+ touchableInputWrapperStyle,
containerStyles,
inputStyle,
forceActiveLabel = false,
@@ -273,7 +274,7 @@ function BaseTextInput(
style={[
autoGrowHeight && styles.autoGrowHeightInputContainer(textInputHeight, variables.componentSizeLarge, typeof maxHeight === 'number' ? maxHeight : 0),
!isMultiline && styles.componentHeightLarge,
- containerStyles,
+ touchableInputWrapperStyle,
]}
>
;
+ /** Customizes the touchable wrapper of the TextInput component */
+ touchableInputWrapperStyle?: StyleProp;
+
/** Customize the main container */
containerStyles?: StyleProp;
diff --git a/src/components/TextPill.tsx b/src/components/TextPill.tsx
new file mode 100644
index 000000000000..6d473b189534
--- /dev/null
+++ b/src/components/TextPill.tsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import type {StyleProp, TextStyle} from 'react-native';
+// eslint-disable-next-line no-restricted-imports
+import useThemeStyles from '@hooks/useThemeStyles';
+import colors from '@styles/theme/colors';
+import Text from './Text';
+
+type TextPillProps = {
+ /** The color of the text/ */
+ color?: string;
+
+ /** Styles to apply to the text */
+ textStyles: StyleProp;
+
+ children: React.ReactNode;
+};
+
+function TextPill({color, textStyles, children}: TextPillProps) {
+ const styles = useThemeStyles();
+
+ return {children};
+}
+
+TextPill.displayName = 'TextPill';
+
+export default TextPill;
diff --git a/src/components/ThemeIllustrationsProvider.tsx b/src/components/ThemeIllustrationsProvider.tsx
index 3b83a00960a4..1d54d6782daf 100644
--- a/src/components/ThemeIllustrationsProvider.tsx
+++ b/src/components/ThemeIllustrationsProvider.tsx
@@ -1,7 +1,8 @@
import React, {useMemo} from 'react';
import useThemePreference from '@hooks/useThemePreference';
import ThemeIllustrationsContext from '@styles/theme/context/ThemeIllustrationsContext';
-import Illustrations from '@styles/theme/illustrations';
+// eslint-disable-next-line no-restricted-imports
+import illustrations from '@styles/theme/illustrations';
type ThemeIllustrationsProviderProps = {
children: React.ReactNode;
@@ -10,9 +11,9 @@ type ThemeIllustrationsProviderProps = {
function ThemeIllustrationsProvider({children}: ThemeIllustrationsProviderProps) {
const themePreference = useThemePreference();
- const illustrations = useMemo(() => Illustrations[themePreference], [themePreference]);
+ const themeIllustrations = useMemo(() => illustrations[themePreference], [themePreference]);
- return {children};
+ return {children};
}
ThemeIllustrationsProvider.displayName = 'ThemeIllustrationsProvider';
diff --git a/src/components/ThemeProvider.tsx b/src/components/ThemeProvider.tsx
index f3d2d9e64ca7..76371bbbc9e1 100644
--- a/src/components/ThemeProvider.tsx
+++ b/src/components/ThemeProvider.tsx
@@ -2,6 +2,7 @@
import PropTypes from 'prop-types';
import React, {useMemo} from 'react';
import useThemePreferenceWithStaticOverride from '@hooks/useThemePreferenceWithStaticOverride';
+// eslint-disable-next-line no-restricted-imports
import themes from '@styles/theme';
import ThemeContext from '@styles/theme/context/ThemeContext';
import type {ThemePreferenceWithoutSystem} from '@styles/theme/types';
diff --git a/src/components/ThemeStylesProvider.tsx b/src/components/ThemeStylesProvider.tsx
index f0d25d9e4dde..3d9431e51446 100644
--- a/src/components/ThemeStylesProvider.tsx
+++ b/src/components/ThemeStylesProvider.tsx
@@ -1,7 +1,9 @@
import React, {useMemo} from 'react';
import useTheme from '@hooks/useTheme';
-import stylesGenerator from '@styles/index';
+// eslint-disable-next-line no-restricted-imports
+import styles from '@styles/index';
import ThemeStylesContext from '@styles/theme/context/ThemeStylesContext';
+// eslint-disable-next-line no-restricted-imports
import createStyleUtils from '@styles/utils';
type ThemeStylesProviderProps = React.PropsWithChildren;
@@ -9,9 +11,9 @@ type ThemeStylesProviderProps = React.PropsWithChildren;
function ThemeStylesProvider({children}: ThemeStylesProviderProps) {
const theme = useTheme();
- const styles = useMemo(() => stylesGenerator(theme), [theme]);
- const StyleUtils = useMemo(() => createStyleUtils(theme, styles), [theme, styles]);
- const contextValue = useMemo(() => ({styles, StyleUtils}), [styles, StyleUtils]);
+ const themeStyles = useMemo(() => styles(theme), [theme]);
+ const StyleUtils = useMemo(() => createStyleUtils(theme, themeStyles), [theme, themeStyles]);
+ const contextValue = useMemo(() => ({styles: themeStyles, StyleUtils}), [themeStyles, StyleUtils]);
return {children};
}
diff --git a/src/components/TimePicker/TimePicker.js b/src/components/TimePicker/TimePicker.js
index 20f52e2d08ee..a9b4566a390c 100644
--- a/src/components/TimePicker/TimePicker.js
+++ b/src/components/TimePicker/TimePicker.js
@@ -469,7 +469,7 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
setSelectionHour(e.nativeEvent.selection);
}}
style={styles.timePickerInput}
- containerStyles={[styles.timePickerHeight100]}
+ touchableInputWrapperStyle={styles.timePickerHeight100}
selection={selectionHour}
showSoftInputOnFocus={false}
/>
@@ -497,7 +497,7 @@ function TimePicker({forwardedRef, defaultValue, onSubmit, onInputChange}) {
setSelectionMinute(e.nativeEvent.selection);
}}
style={styles.timePickerInput}
- containerStyles={[styles.timePickerHeight100]}
+ touchableInputWrapperStyle={styles.timePickerHeight100}
selection={selectionMinute}
showSoftInputOnFocus={false}
/>
diff --git a/src/components/Tooltip/BaseTooltip/index.tsx b/src/components/Tooltip/BaseTooltip/index.tsx
index cf249a936f0b..2487cbbfe092 100644
--- a/src/components/Tooltip/BaseTooltip/index.tsx
+++ b/src/components/Tooltip/BaseTooltip/index.tsx
@@ -10,9 +10,9 @@ import useLocalize from '@hooks/useLocalize';
import usePrevious from '@hooks/usePrevious';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import StringUtils from '@libs/StringUtils';
import variables from '@styles/variables';
import CONST from '@src/CONST';
-import StringUtils from '@src/libs/StringUtils';
import callOrReturn from '@src/types/utils/callOrReturn';
const hasHoverSupport = DeviceCapabilities.hasHoverSupport();
@@ -185,6 +185,16 @@ function Tooltip(
setIsVisible(false);
}, []);
+ const updateTargetPositionOnMouseEnter = useCallback(
+ (e: MouseEvent) => {
+ updateTargetAndMousePosition(e);
+ if (React.isValidElement(children)) {
+ children.props.onMouseEnter?.(e);
+ }
+ },
+ [children, updateTargetAndMousePosition],
+ );
+
// Skip the tooltip and return the children if the text is empty,
// we don't have a render function or the device does not support hovering
if ((StringUtils.isEmptyString(text) && renderTooltipContent == null) || !hasHoverSupport) {
@@ -212,20 +222,30 @@ function Tooltip(
key={[text, ...renderTooltipContentKey, preferredLocale].join('-')}
/>
)}
-
-
- {children}
-
-
+
+ {
+ // Checks if valid element so we can wrap the BoundsObserver around it
+ // If not, we just return the primitive children
+ React.isValidElement(children) ? (
+
+
+ {React.cloneElement(children as React.ReactElement, {
+ onMouseEnter: updateTargetPositionOnMouseEnter,
+ })}
+
+
+ ) : (
+ children
+ )
+ }
>
);
}
diff --git a/src/components/ValidateCode/ValidateCodeModal.tsx b/src/components/ValidateCode/ValidateCodeModal.tsx
index 9c83a80b0d24..1e42773c2dc2 100644
--- a/src/components/ValidateCode/ValidateCodeModal.tsx
+++ b/src/components/ValidateCode/ValidateCodeModal.tsx
@@ -40,7 +40,6 @@ function ValidateCodeModal({code, accountID, session = {}}: ValidateCodeModalPro
diff --git a/src/components/ValuePicker/ValueSelectorModal.js b/src/components/ValuePicker/ValueSelectorModal.js
index edc5a48d0bb3..e45ba873d8a3 100644
--- a/src/components/ValuePicker/ValueSelectorModal.js
+++ b/src/components/ValuePicker/ValueSelectorModal.js
@@ -26,6 +26,9 @@ const propTypes = {
/** Function to call when the user closes the modal */
onClose: PropTypes.func,
+
+ /** Whether to show the toolip text */
+ shouldShowTooltips: PropTypes.bool,
};
const defaultProps = {
@@ -34,14 +37,15 @@ const defaultProps = {
label: '',
onClose: () => {},
onItemSelected: () => {},
+ shouldShowTooltips: true,
};
-function ValueSelectorModal({items, selectedItem, label, isVisible, onClose, onItemSelected}) {
+function ValueSelectorModal({items, selectedItem, label, isVisible, onClose, onItemSelected, shouldShowTooltips}) {
const styles = useThemeStyles();
const [sectionsData, setSectionsData] = useState([]);
useEffect(() => {
- const itemsData = _.map(items, (item) => ({value: item.value, keyForList: item.value, text: item.label, isSelected: item === selectedItem}));
+ const itemsData = _.map(items, (item) => ({value: item.value, alternateText: item.description, keyForList: item.value, text: item.label, isSelected: item === selectedItem}));
setSectionsData(itemsData);
}, [items, selectedItem]);
@@ -69,6 +73,7 @@ function ValueSelectorModal({items, selectedItem, label, isVisible, onClose, onI
onSelectRow={onItemSelected}
initiallyFocusedOptionKey={selectedItem.value}
shouldStopPropagation
+ shouldShowTooltips={shouldShowTooltips}
/>
diff --git a/src/components/ValuePicker/index.js b/src/components/ValuePicker/index.js
index b5ddaa7dcb73..d90529114af4 100644
--- a/src/components/ValuePicker/index.js
+++ b/src/components/ValuePicker/index.js
@@ -29,8 +29,14 @@ const propTypes = {
/** Callback to call when the input changes */
onInputChange: PropTypes.func,
+ /** Text to display under the main menu item */
+ furtherDetails: PropTypes.string,
+
/** A ref to forward to MenuItemWithTopDescription */
forwardedRef: refPropTypes,
+
+ /** Whether to show the toolip text */
+ shouldShowTooltips: PropTypes.bool,
};
const defaultProps = {
@@ -40,10 +46,12 @@ const defaultProps = {
items: {},
forwardedRef: undefined,
errorText: '',
+ furtherDetails: undefined,
onInputChange: () => {},
+ shouldShowTooltips: true,
};
-function ValuePicker({value, label, items, placeholder, errorText, onInputChange, forwardedRef}) {
+function ValuePicker({value, label, items, placeholder, errorText, onInputChange, furtherDetails, shouldShowTooltips, forwardedRef}) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const [isPickerVisible, setIsPickerVisible] = useState(false);
@@ -63,7 +71,7 @@ function ValuePicker({value, label, items, placeholder, errorText, onInputChange
hidePickerModal();
};
- const descStyle = value.length === 0 ? StyleUtils.getFontSizeStyle(variables.fontSizeLabel) : null;
+ const descStyle = !value || value.length === 0 ? StyleUtils.getFontSizeStyle(variables.fontSizeLabel) : null;
const selectedItem = _.find(items, {value});
const selectedLabel = selectedItem ? selectedItem.label : '';
@@ -76,6 +84,7 @@ function ValuePicker({value, label, items, placeholder, errorText, onInputChange
descriptionTextStyle={descStyle}
description={label}
onPress={showPickerModal}
+ furtherDetails={furtherDetails}
/>
@@ -87,6 +96,7 @@ function ValuePicker({value, label, items, placeholder, errorText, onInputChange
items={items}
onClose={hidePickerModal}
onItemSelected={updateInput}
+ shouldShowTooltips={shouldShowTooltips}
/>
);
diff --git a/src/components/ViolationMessages.tsx b/src/components/ViolationMessages.tsx
new file mode 100644
index 000000000000..8eb555184596
--- /dev/null
+++ b/src/components/ViolationMessages.tsx
@@ -0,0 +1,26 @@
+import React, {useMemo} from 'react';
+import {View} from 'react-native';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import ViolationsUtils from '@libs/ViolationsUtils';
+import type {TransactionViolation} from '@src/types/onyx';
+import Text from './Text';
+
+export default function ViolationMessages({violations, isLast}: {violations: TransactionViolation[]; isLast?: boolean}) {
+ const styles = useThemeStyles();
+ const {translate} = useLocalize();
+ const violationMessages = useMemo(() => violations.map((violation) => [violation.name, ViolationsUtils.getViolationTranslation(violation, translate)]), [translate, violations]);
+
+ return (
+
+ {violationMessages.map(([name, message]) => (
+
+ {message}
+
+ ))}
+
+ );
+}
diff --git a/src/components/menuItemPropTypes.js b/src/components/menuItemPropTypes.js
index 21e74b61b9c4..83d2feca7a0a 100644
--- a/src/components/menuItemPropTypes.js
+++ b/src/components/menuItemPropTypes.js
@@ -164,6 +164,9 @@ const propTypes = {
/** Should check anonymous user in onPress function */
shouldCheckActionAllowedOnPress: PropTypes.bool,
+ /** The menu item link or function to get the link */
+ link: PropTypes.oneOfType(PropTypes.func, PropTypes.string),
+
/** Icon should be displayed in its own color */
displayInDefaultIconColor: PropTypes.bool,
};
diff --git a/src/components/withKeyboardState.tsx b/src/components/withKeyboardState.tsx
index 2a74fd3e738e..74d10945fbcb 100755
--- a/src/components/withKeyboardState.tsx
+++ b/src/components/withKeyboardState.tsx
@@ -16,7 +16,9 @@ const keyboardStatePropTypes = {
isKeyboardShown: PropTypes.bool.isRequired,
};
-const KeyboardStateContext = createContext(null);
+const KeyboardStateContext = createContext({
+ isKeyboardShown: false,
+});
function KeyboardStateProvider({children}: ChildrenProps): ReactElement | null {
const [isKeyboardShown, setIsKeyboardShown] = useState(false);
diff --git a/src/components/withNavigationFocus.tsx b/src/components/withNavigationFocus.tsx
index 90a674a2e56e..bd7a39620114 100644
--- a/src/components/withNavigationFocus.tsx
+++ b/src/components/withNavigationFocus.tsx
@@ -25,3 +25,5 @@ export default function withNavigationFocus null;
-
-export default useActiveElement;
diff --git a/src/hooks/useActiveElement/types.ts b/src/hooks/useActiveElement/types.ts
deleted file mode 100644
index f3b5193975a5..000000000000
--- a/src/hooks/useActiveElement/types.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-type UseActiveElement = () => Element | null;
-
-export default UseActiveElement;
diff --git a/src/hooks/useActiveElementRole/index.native.ts b/src/hooks/useActiveElementRole/index.native.ts
new file mode 100644
index 000000000000..4278014f02a8
--- /dev/null
+++ b/src/hooks/useActiveElementRole/index.native.ts
@@ -0,0 +1,8 @@
+import type UseActiveElementRole from './types';
+
+/**
+ * Native doesn't have the DOM, so we just return null.
+ */
+const useActiveElementRole: UseActiveElementRole = () => null;
+
+export default useActiveElementRole;
diff --git a/src/hooks/useActiveElement/index.ts b/src/hooks/useActiveElementRole/index.ts
similarity index 59%
rename from src/hooks/useActiveElement/index.ts
rename to src/hooks/useActiveElementRole/index.ts
index 6026b4f5eb80..a98999105ac8 100644
--- a/src/hooks/useActiveElement/index.ts
+++ b/src/hooks/useActiveElementRole/index.ts
@@ -1,19 +1,19 @@
-import {useEffect, useState} from 'react';
-import type UseActiveElement from './types';
+import {useEffect, useRef} from 'react';
+import type UseActiveElementRole from './types';
/**
* Listens for the focusin and focusout events and sets the DOM activeElement to the state.
* On native, we just return null.
*/
-const useActiveElement: UseActiveElement = () => {
- const [active, setActive] = useState(document.activeElement);
+const useActiveElementRole: UseActiveElementRole = () => {
+ const activeRoleRef = useRef(document?.activeElement?.role);
const handleFocusIn = () => {
- setActive(document.activeElement);
+ activeRoleRef.current = document?.activeElement?.role;
};
const handleFocusOut = () => {
- setActive(null);
+ activeRoleRef.current = null;
};
useEffect(() => {
@@ -26,7 +26,7 @@ const useActiveElement: UseActiveElement = () => {
};
}, []);
- return active;
+ return activeRoleRef.current;
};
-export default useActiveElement;
+export default useActiveElementRole;
diff --git a/src/hooks/useActiveElementRole/types.ts b/src/hooks/useActiveElementRole/types.ts
new file mode 100644
index 000000000000..c31b8ab7ddbf
--- /dev/null
+++ b/src/hooks/useActiveElementRole/types.ts
@@ -0,0 +1,3 @@
+type UseActiveElementRole = () => string | null | undefined;
+
+export default UseActiveElementRole;
diff --git a/src/hooks/useDebouncedState.ts b/src/hooks/useDebouncedState.ts
new file mode 100644
index 000000000000..3677c85f3081
--- /dev/null
+++ b/src/hooks/useDebouncedState.ts
@@ -0,0 +1,35 @@
+import debounce from 'lodash/debounce';
+import {useEffect, useRef, useState} from 'react';
+import CONST from '@src/CONST';
+
+/**
+ * A React hook that provides a state and its debounced version.
+ *
+ * @param initialValue - The initial value of the state.
+ * @param delay - The debounce delay in milliseconds. Defaults to SEARCH_OPTION_LIST_DEBOUNCE_TIME = 300ms.
+ * @returns A tuple containing:
+ * - The current state value.
+ * - The debounced state value.
+ * - A function to set both the current and debounced state values.
+ *
+ * @template T The type of the state value.
+ *
+ * @example
+ * const [value, debouncedValue, setValue] = useDebouncedState("", 300);
+ */
+function useDebouncedState(initialValue: T, delay = CONST.TIMING.SEARCH_OPTION_LIST_DEBOUNCE_TIME): [T, T, (value: T) => void] {
+ const [value, setValue] = useState(initialValue);
+ const [debouncedValue, setDebouncedValue] = useState(initialValue);
+ const debouncedSetDebouncedValue = useRef(debounce(setDebouncedValue, delay)).current;
+
+ useEffect(() => () => debouncedSetDebouncedValue.cancel(), [debouncedSetDebouncedValue]);
+
+ const handleSetValue = (newValue: T) => {
+ setValue(newValue);
+ debouncedSetDebouncedValue(newValue);
+ };
+
+ return [value, debouncedValue, handleSetValue];
+}
+
+export default useDebouncedState;
diff --git a/src/hooks/useKeyboardState.ts b/src/hooks/useKeyboardState.ts
index 439f626ddcdd..60ad3b8975b1 100644
--- a/src/hooks/useKeyboardState.ts
+++ b/src/hooks/useKeyboardState.ts
@@ -6,6 +6,6 @@ import {KeyboardStateContext} from '@components/withKeyboardState';
* Hook for getting current state of keyboard
* whether the keyboard is open
*/
-export default function useKeyboardState(): KeyboardStateContextValue | null {
+export default function useKeyboardState(): KeyboardStateContextValue {
return useContext(KeyboardStateContext);
}
diff --git a/src/hooks/useResponsiveLayout.ts b/src/hooks/useResponsiveLayout.ts
index dd782a9dbba5..3ca2482ec387 100644
--- a/src/hooks/useResponsiveLayout.ts
+++ b/src/hooks/useResponsiveLayout.ts
@@ -3,7 +3,7 @@ import {useRoute} from '@react-navigation/native';
import useWindowDimensions from './useWindowDimensions';
type RouteParams = ParamListBase & {
- params: {isInRHP?: boolean};
+ params: {layout?: string};
};
type ResponsiveLayoutResult = {
shouldUseNarrowLayout: boolean;
@@ -16,10 +16,11 @@ export default function useResponsiveLayout(): ResponsiveLayoutResult {
try {
// eslint-disable-next-line react-hooks/rules-of-hooks
const {params} = useRoute>();
- return {shouldUseNarrowLayout: isSmallScreenWidth || (params?.isInRHP ?? false)};
+ const isNarrowLayout = params?.layout === 'narrow' ?? false;
+ const shouldUseNarrowLayout = isSmallScreenWidth || isNarrowLayout;
+
+ return {shouldUseNarrowLayout};
} catch (error) {
- return {
- shouldUseNarrowLayout: isSmallScreenWidth,
- };
+ return {shouldUseNarrowLayout: isSmallScreenWidth};
}
}
diff --git a/src/hooks/useSingleExecution/index.ts b/src/hooks/useSingleExecution/index.ts
index f1be359f0355..909416dd848b 100644
--- a/src/hooks/useSingleExecution/index.ts
+++ b/src/hooks/useSingleExecution/index.ts
@@ -9,9 +9,9 @@ type Action = (...params: T) => void | Promise;
*/
export default function useSingleExecution() {
const singleExecution = useCallback(
- (action: Action) =>
+ (action?: Action) =>
(...params: T) => {
- action(...params);
+ action?.(...params);
},
[],
);
diff --git a/src/hooks/useViolations.ts b/src/hooks/useViolations.ts
index 0f43abdff6e2..76d48158237b 100644
--- a/src/hooks/useViolations.ts
+++ b/src/hooks/useViolations.ts
@@ -2,12 +2,12 @@ import {useCallback, useMemo} from 'react';
import type {TransactionViolation, ViolationName} from '@src/types/onyx';
/**
- * Names of Fields where violations can occur
+ * Names of Fields where violations can occur.
*/
type ViolationField = 'amount' | 'billable' | 'category' | 'comment' | 'date' | 'merchant' | 'receipt' | 'tag' | 'tax';
/**
- * Map from Violation Names to the field where that violation can occur
+ * Map from Violation Names to the field where that violation can occur.
*/
const violationFields: Record = {
allTagLevelsRequired: 'tag',
@@ -60,13 +60,12 @@ function useViolations(violations: TransactionViolation[]) {
return violationGroups ?? new Map();
}, [violations]);
- const hasViolations = useCallback((field: ViolationField) => Boolean(violationsByField.get(field)?.length), [violationsByField]);
const getViolationsForField = useCallback((field: ViolationField) => violationsByField.get(field) ?? [], [violationsByField]);
return {
- hasViolations,
getViolationsForField,
};
}
export default useViolations;
+export type {ViolationField};
diff --git a/src/languages/en.ts b/src/languages/en.ts
index e223dd0a9aaf..09fd295cb859 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -2,6 +2,7 @@ import {CONST as COMMON_CONST} from 'expensify-common/lib/CONST';
import CONST from '@src/CONST';
import type {
AddressLineParams,
+ AdminCanceledRequestParams,
AlreadySignedInParams,
AmountEachParams,
ApprovedAmountParams,
@@ -73,7 +74,22 @@ import type {
UntilTimeParams,
UpdatedTheDistanceParams,
UpdatedTheRequestParams,
+ UsePlusButtonParams,
UserIsAlreadyMemberParams,
+ ViolationsAutoReportedRejectedExpenseParams,
+ ViolationsCashExpenseWithNoReceiptParams,
+ ViolationsConversionSurchargeParams,
+ ViolationsInvoiceMarkupParams,
+ ViolationsMaxAgeParams,
+ ViolationsMissingTagParams,
+ ViolationsOverAutoApprovalLimitParams,
+ ViolationsOverCategoryLimitParams,
+ ViolationsOverLimitParams,
+ ViolationsPerDayLimitParams,
+ ViolationsReceiptRequiredParams,
+ ViolationsRterParams,
+ ViolationsTagOutOfPolicyParams,
+ ViolationsTaxOutOfPolicyParams,
WaitingOnBankAccountParams,
WalletProgramParams,
WelcomeEnterMagicCodeParams,
@@ -96,6 +112,7 @@ type AllCountries = Record;
export default {
common: {
cancel: 'Cancel',
+ dismiss: 'Dismiss',
yes: 'Yes',
no: 'No',
ok: 'OK',
@@ -467,7 +484,12 @@ export default {
chatWithAccountManager: 'Chat with your account manager here',
sayHello: 'Say hello!',
welcomeToRoom: ({roomName}: WelcomeToRoomParams) => `Welcome to ${roomName}!`,
- usePlusButton: '\n\nYou can also use the + button to send money, request money, or assign a task!',
+ usePlusButton: ({additionalText}: UsePlusButtonParams) => `\n\nYou can also use the + button to ${additionalText}, or assign a task!`,
+ iouTypes: {
+ send: 'send money',
+ split: 'split a bill',
+ request: 'request money',
+ },
},
reportAction: {
asCopilot: 'as copilot for',
@@ -553,6 +575,8 @@ export default {
requestMoney: 'Request money',
sendMoney: 'Send money',
pay: 'Pay',
+ cancelPayment: 'Cancel payment',
+ cancelPaymentConfirmation: 'Are you sure that you want to cancel this payment?',
viewDetails: 'View details',
pending: 'Pending',
canceled: 'Canceled',
@@ -589,6 +613,7 @@ export default {
payerSettled: ({amount}: PayerSettledParams) => `paid ${amount}`,
approvedAmount: ({amount}: ApprovedAmountParams) => `approved ${amount}`,
waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `started settling up, payment is held until ${submitterDisplayName} adds a bank account`,
+ adminCanceledRequest: ({amount}: AdminCanceledRequestParams) => `The ${amount} payment has been cancelled by the admin.`,
canceledRequest: ({amount, submitterDisplayName}: CanceledRequestParams) =>
`Canceled the ${amount} payment, because ${submitterDisplayName} did not enable their Expensify Wallet within 30 days`,
settledAfterAddedBankAccount: ({submitterDisplayName, amount}: SettledAfterAddedBankAccountParams) =>
@@ -621,12 +646,21 @@ export default {
genericDeleteFailureMessage: 'Unexpected error deleting the money request, please try again later',
genericEditFailureMessage: 'Unexpected error editing the money request, please try again later',
genericSmartscanFailureMessage: 'Transaction is missing fields',
+ duplicateWaypointsErrorMessage: 'Please remove duplicate waypoints',
atLeastTwoDifferentWaypoints: 'Please enter at least two different addresses',
splitBillMultipleParticipantsErrorMessage: 'Split bill is only allowed between a single workspace or individual users. Please update your selection.',
invalidMerchant: 'Please enter a correct merchant.',
},
waitingOnEnabledWallet: ({submitterDisplayName}: WaitingOnBankAccountParams) => `Started settling up, payment is held until ${submitterDisplayName} enables their Wallet`,
enableWallet: 'Enable Wallet',
+ hold: 'Hold',
+ holdEducationalTitle: 'This request is on',
+ whatIsHoldTitle: 'What is hold?',
+ whatIsHoldExplain: 'Hold is our way of streamlining financial collaboration. "Reject" is so harsh!',
+ holdIsTemporaryTitle: 'Hold is usually temporary',
+ holdIsTemporaryExplain: "Because hold is used to clear up confusion or clarify an important detail before payment, it's not permanent.",
+ deleteHoldTitle: "Delete whatever won't be paid",
+ deleteHoldExplain: "In the rare case where something is put on hold and won't be paid, it's on the person requesting payment to delete it.",
set: 'set',
changed: 'changed',
removed: 'removed',
@@ -1535,7 +1569,7 @@ export default {
noVBACopy: 'Connect a bank account to issue Expensify Cards to your workspace members, and access these incredible benefits and more:',
VBANoECardCopy: 'Add a work email address to issue unlimited Expensify Cards for your workspace members, as well as all of these incredible benefits:',
VBAWithECardCopy: 'Access these incredible benefits and more:',
- benefit1: 'Up to 4% cash back',
+ benefit1: 'Up to 2% cash back',
benefit2: 'Digital and physical cards',
benefit3: 'No personal liability',
benefit4: 'Customizable limits',
@@ -1937,6 +1971,10 @@ export default {
levelTwoResult: 'Message hidden from channel, plus anonymous warning and message is reported for review.',
levelThreeResult: 'Message removed from channel plus anonymous warning and message is reported for review.',
},
+ actionableMentionWhisperOptions: {
+ invite: 'Invite them',
+ nothing: 'Do nothing',
+ },
teachersUnitePage: {
teachersUnite: 'Teachers Unite',
joinExpensifyOrg: 'Join Expensify.org in eliminating injustice around the world and help teachers split their expenses for classrooms in need!',
@@ -2007,66 +2045,77 @@ export default {
buttonText1: 'Start a chat, ',
buttonText2: `get $${CONST.REFERRAL_PROGRAM.REVENUE}.`,
header: `Start a chat, get $${CONST.REFERRAL_PROGRAM.REVENUE}`,
- body: `Get paid to talk to your friends! Start a chat with a new Expensify account and get $${CONST.REFERRAL_PROGRAM.REVENUE} if they become an Expensify customer.`,
+ body: `Get paid to talk to your friends! Start a chat with a new Expensify account and get $${CONST.REFERRAL_PROGRAM.REVENUE} when they become a customer.`,
},
[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.MONEY_REQUEST]: {
buttonText1: 'Request money, ',
buttonText2: `get $${CONST.REFERRAL_PROGRAM.REVENUE}.`,
header: `Request money, get $${CONST.REFERRAL_PROGRAM.REVENUE}`,
- body: `It pays to get paid! Request money from a new Expensify account and get $${CONST.REFERRAL_PROGRAM.REVENUE} if they become an Expensify customer.`,
+ body: `It pays to get paid! Request money from a new Expensify account and get $${CONST.REFERRAL_PROGRAM.REVENUE} when they become a customer.`,
},
[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SEND_MONEY]: {
buttonText1: 'Send money, ',
buttonText2: `get $${CONST.REFERRAL_PROGRAM.REVENUE}.`,
header: `Send money, get $${CONST.REFERRAL_PROGRAM.REVENUE}`,
- body: `You gotta send money to make money! Send money to a new Expensify account and get $${CONST.REFERRAL_PROGRAM.REVENUE} if they become an Expensify customer.`,
+ body: `You gotta send money to make money! Send money to a new Expensify account and get $${CONST.REFERRAL_PROGRAM.REVENUE} when they become a customer.`,
},
[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND]: {
buttonText1: 'Invite a friend, ',
buttonText2: `get $${CONST.REFERRAL_PROGRAM.REVENUE}.`,
header: `Get $${CONST.REFERRAL_PROGRAM.REVENUE}`,
- body: `Start a chat, send or request money, split a bill, or share your invite link below with a new Expensify account and get $${CONST.REFERRAL_PROGRAM.REVENUE} if they become an Expensify customer. Learn more ways to earn below.`,
+ body: `Be the first to chat, send or request money, split a bill, or share your invite link with a friend, and you'll get $${CONST.REFERRAL_PROGRAM.REVENUE} when they become a customer. You can post your invite link on social media, too!`,
},
[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SHARE_CODE]: {
buttonText1: `Get $${CONST.REFERRAL_PROGRAM.REVENUE}`,
header: `Get $${CONST.REFERRAL_PROGRAM.REVENUE}`,
- body: `Start a chat, send or request money, split a bill, or share your invite link below with a new Expensify account and get $${CONST.REFERRAL_PROGRAM.REVENUE} if they become an Expensify customer. Learn more ways to earn below.`,
+ body: `Be the first to chat, send or request money, split a bill, or share your invite link with a friend, and you'll get $${CONST.REFERRAL_PROGRAM.REVENUE} when they become a customer. You can post your invite link on social media, too!`,
},
copyReferralLink: 'Copy invite link',
},
violations: {
- allTagLevelsRequired: 'dummy.violations.allTagLevelsRequired',
- autoReportedRejectedExpense: 'dummy.violations.autoReportedRejectedExpense',
- billableExpense: 'dummy.violations.billableExpense',
- cashExpenseWithNoReceipt: 'dummy.violations.cashExpenseWithNoReceipt',
- categoryOutOfPolicy: 'dummy.violations.categoryOutOfPolicy',
- conversionSurcharge: 'dummy.violations.conversionSurcharge',
- customUnitOutOfPolicy: 'dummy.violations.customUnitOutOfPolicy',
- duplicatedTransaction: 'dummy.violations.duplicatedTransaction',
- fieldRequired: 'dummy.violations.fieldRequired',
- futureDate: 'dummy.violations.futureDate',
- invoiceMarkup: 'dummy.violations.invoiceMarkup',
- maxAge: 'dummy.violations.maxAge',
- missingCategory: 'dummy.violations.missingCategory',
- missingComment: 'dummy.violations.missingComment',
- missingTag: 'dummy.violations.missingTag',
- modifiedAmount: 'dummy.violations.modifiedAmount',
- modifiedDate: 'dummy.violations.modifiedDate',
- nonExpensiworksExpense: 'dummy.violations.nonExpensiworksExpense',
- overAutoApprovalLimit: 'dummy.violations.overAutoApprovalLimit',
- overCategoryLimit: 'dummy.violations.overCategoryLimit',
- overLimit: 'dummy.violations.overLimit',
- overLimitAttendee: 'dummy.violations.overLimitAttendee',
- perDayLimit: 'dummy.violations.perDayLimit',
- receiptNotSmartScanned: 'dummy.violations.receiptNotSmartScanned',
- receiptRequired: 'dummy.violations.receiptRequired',
- rter: 'dummy.violations.rter',
- smartscanFailed: 'dummy.violations.smartscanFailed',
- someTagLevelsRequired: 'dummy.violations.someTagLevelsRequired',
- tagOutOfPolicy: 'dummy.violations.tagOutOfPolicy',
- taxAmountChanged: 'dummy.violations.taxAmountChanged',
- taxOutOfPolicy: 'dummy.violations.taxOutOfPolicy',
- taxRateChanged: 'dummy.violations.taxRateChanged',
- taxRequired: 'dummy.violations.taxRequired',
+ allTagLevelsRequired: 'All tags required',
+ autoReportedRejectedExpense: ({rejectReason, rejectedBy}: ViolationsAutoReportedRejectedExpenseParams) => `${rejectedBy} rejected this expense with the comment "${rejectReason}"`,
+ billableExpense: 'Billable no longer valid',
+ cashExpenseWithNoReceipt: ({amount}: ViolationsCashExpenseWithNoReceiptParams) => `Receipt required over ${amount}`,
+ categoryOutOfPolicy: 'Category no longer valid',
+ conversionSurcharge: ({surcharge}: ViolationsConversionSurchargeParams) => `Applied ${surcharge}% conversion surcharge`,
+ customUnitOutOfPolicy: 'Unit no longer valid',
+ duplicatedTransaction: 'Potential duplicate',
+ fieldRequired: 'Report fields are required',
+ futureDate: 'Future date not allowed',
+ invoiceMarkup: ({invoiceMarkup}: ViolationsInvoiceMarkupParams) => `Marked up by ${invoiceMarkup}%`,
+ maxAge: ({maxAge}: ViolationsMaxAgeParams) => `Date older than ${maxAge} days`,
+ missingCategory: 'Missing category',
+ missingComment: 'Description required for selected category',
+ missingTag: ({tagName}: ViolationsMissingTagParams) => `Missing ${tagName ?? 'tag'}`,
+ modifiedAmount: 'Amount greater than scanned receipt',
+ modifiedDate: 'Date differs from scanned receipt',
+ nonExpensiworksExpense: 'Non-Expensiworks expense',
+ overAutoApprovalLimit: ({formattedLimitAmount}: ViolationsOverAutoApprovalLimitParams) => `Expense exceeds auto approval limit of ${formattedLimitAmount}`,
+ overCategoryLimit: ({categoryLimit}: ViolationsOverCategoryLimitParams) => `Amount over ${categoryLimit}/person category limit`,
+ overLimit: ({amount}: ViolationsOverLimitParams) => `Amount over ${amount}/person limit`,
+ overLimitAttendee: ({amount}: ViolationsOverLimitParams) => `Amount over ${amount}/person limit`,
+ perDayLimit: ({limit}: ViolationsPerDayLimitParams) => `Amount over daily ${limit}/person category limit`,
+ receiptNotSmartScanned: 'Receipt not verified. Please confirm accuracy.',
+ receiptRequired: ({amount, category}: ViolationsReceiptRequiredParams) => `Receipt required over ${amount} ${category ? ' category limit' : ''}`,
+ rter: ({brokenBankConnection, email, isAdmin, isTransactionOlderThan7Days, member}: ViolationsRterParams) => {
+ if (brokenBankConnection) {
+ return isAdmin
+ ? `Can't auto-match receipt due to broken bank connection which ${email} needs to fix`
+ : "Can't auto-match receipt due to broken bank connection which you need to fix";
+ }
+ if (!isTransactionOlderThan7Days) {
+ return isAdmin ? `Ask ${member} to mark as a cash or wait 7 days and try again` : 'Awaiting merge with card transaction.';
+ }
+
+ return '';
+ },
+ smartscanFailed: 'Receipt scanning failed. Enter details manually.',
+ someTagLevelsRequired: 'Missing tag',
+ tagOutOfPolicy: ({tagName}: ViolationsTagOutOfPolicyParams) => `${tagName ?? ''} no longer valid`,
+ taxAmountChanged: 'Tax amount was modified',
+ taxOutOfPolicy: ({taxName}: ViolationsTaxOutOfPolicyParams) => `${taxName ?? ''} no longer valid`,
+ taxRateChanged: 'Tax rate was modified',
+ taxRequired: 'Missing tax rate',
},
} satisfies TranslationBase;
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 42743f43a098..b977a614ae7e 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -1,6 +1,7 @@
import CONST from '@src/CONST';
import type {
AddressLineParams,
+ AdminCanceledRequestParams,
AlreadySignedInParams,
AmountEachParams,
ApprovedAmountParams,
@@ -72,7 +73,22 @@ import type {
UntilTimeParams,
UpdatedTheDistanceParams,
UpdatedTheRequestParams,
+ UsePlusButtonParams,
UserIsAlreadyMemberParams,
+ ViolationsAutoReportedRejectedExpenseParams,
+ ViolationsCashExpenseWithNoReceiptParams,
+ ViolationsConversionSurchargeParams,
+ ViolationsInvoiceMarkupParams,
+ ViolationsMaxAgeParams,
+ ViolationsMissingTagParams,
+ ViolationsOverAutoApprovalLimitParams,
+ ViolationsOverCategoryLimitParams,
+ ViolationsOverLimitParams,
+ ViolationsPerDayLimitParams,
+ ViolationsReceiptRequiredParams,
+ ViolationsRterParams,
+ ViolationsTagOutOfPolicyParams,
+ ViolationsTaxOutOfPolicyParams,
WaitingOnBankAccountParams,
WalletProgramParams,
WelcomeEnterMagicCodeParams,
@@ -86,6 +102,7 @@ import type {
export default {
common: {
cancel: 'Cancelar',
+ dismiss: 'Descartar',
yes: 'Sí',
no: 'No',
ok: 'OK',
@@ -460,7 +477,12 @@ export default {
chatWithAccountManager: 'Chatea con tu gestor de cuenta aquí',
sayHello: '¡Saluda!',
welcomeToRoom: ({roomName}: WelcomeToRoomParams) => `¡Bienvenido a ${roomName}!`,
- usePlusButton: '\n\n¡También puedes usar el botón + de abajo para enviar dinero, pedir dinero, o asignar una tarea!',
+ usePlusButton: ({additionalText}: UsePlusButtonParams) => `\n\n¡También puedes usar el botón + de abajo para ${additionalText}, o asignar una tarea!`,
+ iouTypes: {
+ send: 'enviar dinero',
+ split: 'dividir una factura',
+ request: 'pedir dinero',
+ },
},
reportAction: {
asCopilot: 'como copiloto de',
@@ -546,6 +568,8 @@ export default {
requestMoney: 'Pedir dinero',
sendMoney: 'Enviar dinero',
pay: 'Pagar',
+ cancelPayment: 'Cancelar el pago',
+ cancelPaymentConfirmation: '¿Estás seguro de que quieres cancelar este pago?',
viewDetails: 'Ver detalles',
pending: 'Pendiente',
canceled: 'Canceló',
@@ -582,6 +606,7 @@ export default {
payerSettled: ({amount}: PayerSettledParams) => `pagó ${amount}`,
approvedAmount: ({amount}: ApprovedAmountParams) => `aprobó ${amount}`,
waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `inicio el pago, pero no se procesará hasta que ${submitterDisplayName} añada una cuenta bancaria`,
+ adminCanceledRequest: ({amount}: AdminCanceledRequestParams) => `El pago de ${amount} ha sido cancelado por el administrador.`,
canceledRequest: ({amount, submitterDisplayName}: CanceledRequestParams) =>
`Canceló el pago ${amount}, porque ${submitterDisplayName} no habilitó su billetera Expensify en un plazo de 30 días.`,
settledAfterAddedBankAccount: ({submitterDisplayName, amount}: SettledAfterAddedBankAccountParams) =>
@@ -616,12 +641,21 @@ export default {
genericDeleteFailureMessage: 'Error inesperado eliminando la solicitud de dinero. Por favor, inténtalo más tarde',
genericEditFailureMessage: 'Error inesperado al guardar la solicitud de dinero. Por favor, inténtalo más tarde',
genericSmartscanFailureMessage: 'La transacción tiene campos vacíos',
+ duplicateWaypointsErrorMessage: 'Por favor elimina los puntos de ruta duplicados',
atLeastTwoDifferentWaypoints: 'Por favor introduce al menos dos direcciones diferentes',
splitBillMultipleParticipantsErrorMessage: 'Solo puedes dividir una cuenta entre un único espacio de trabajo o con usuarios individuales. Por favor actualiza tu selección.',
invalidMerchant: 'Por favor ingrese un comerciante correcto.',
},
waitingOnEnabledWallet: ({submitterDisplayName}: WaitingOnBankAccountParams) => `Inició el pago, pero no se procesará hasta que ${submitterDisplayName} active su Billetera`,
enableWallet: 'Habilitar Billetera',
+ hold: 'Hold',
+ holdEducationalTitle: 'Esta solicitud está en',
+ whatIsHoldTitle: '¿Qué es Hold?',
+ whatIsHoldExplain: 'Hold es nuestra forma de agilizar la colaboración financiera. ¡"Rechazar" es tan duro!',
+ holdIsTemporaryTitle: 'Hold suele ser temporal',
+ holdIsTemporaryExplain: 'Debido a que hold se utiliza para aclarar confusión o aclarar un detalle importante antes del pago, no es permanente.',
+ deleteHoldTitle: 'Eliminar lo que no se pagará',
+ deleteHoldExplain: 'En el raro caso de que algo se ponga en hold y no se pague, la persona que solicita el pago debe eliminarlo.',
set: 'estableció',
changed: 'cambió',
removed: 'eliminó',
@@ -1559,7 +1593,7 @@ export default {
VBANoECardCopy:
'Añade tu correo electrónico de trabajo para emitir Tarjetas Expensify ilimitadas para los miembros de tu espacio de trabajo y acceder a todas estas increíbles ventajas:',
VBAWithECardCopy: 'Acceda a estos increíbles beneficios y más:',
- benefit1: 'Hasta un 4% de devolución en tus gastos',
+ benefit1: 'Hasta un 2% de devolución en tus gastos',
benefit2: 'Tarjetas digitales y físicas',
benefit3: 'Sin responsabilidad personal',
benefit4: 'Límites personalizables',
@@ -1749,7 +1783,7 @@ export default {
messages: {
created: ({title}: TaskCreatedActionParams) => `tarea para ${title}`,
completed: 'marcada como completa',
- canceled: 'tarea eliminado',
+ canceled: 'tarea eliminada',
reopened: 'marcada como incompleta',
error: 'No tiene permiso para realizar la acción solicitada.',
},
@@ -2387,7 +2421,7 @@ export default {
deletedMessage: '[Mensaje eliminado]',
deletedRequest: '[Pedido eliminado]',
reversedTransaction: '[Transacción anulada]',
- deletedTask: '[Tarea eliminado]',
+ deletedTask: '[Tarea eliminada]',
hiddenMessage: '[Mensaje oculto]',
},
threads: {
@@ -2401,6 +2435,10 @@ export default {
copy: 'Copiar',
copied: '¡Copiado!',
},
+ actionableMentionWhisperOptions: {
+ invite: 'Invitar',
+ nothing: 'No hacer nada',
+ },
moderation: {
flagDescription: 'Todos los mensajes marcados se enviarán a un moderador para su revisión.',
chooseAReason: 'Elige abajo un motivo para reportarlo:',
@@ -2494,66 +2532,78 @@ export default {
buttonText1: 'Inicia un chat y ',
buttonText2: `recibe $${CONST.REFERRAL_PROGRAM.REVENUE}`,
header: `Inicia un chat y recibe $${CONST.REFERRAL_PROGRAM.REVENUE}`,
- body: `¡Gana dinero por hablar con tus amigos! Inicia un chat con una cuenta nueva de Expensify y obtiene $${CONST.REFERRAL_PROGRAM.REVENUE} si se convierten en clientes de Expensify.`,
+ body: `¡Gana dinero por hablar con tus amigos! Inicia un chat con una cuenta nueva de Expensify y recibe $${CONST.REFERRAL_PROGRAM.REVENUE} cuando se conviertan en clientes.`,
},
[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.MONEY_REQUEST]: {
buttonText1: 'Pide dinero, ',
buttonText2: `recibe $${CONST.REFERRAL_PROGRAM.REVENUE}`,
header: `Pide dinero y recibe $${CONST.REFERRAL_PROGRAM.REVENUE}`,
- body: `¡Vale la pena cobrar! Pide dinero a una cuenta nueva de Expensify y obtiene $${CONST.REFERRAL_PROGRAM.REVENUE} si se convierten en clientes de Expensify.`,
+ body: `¡Vale la pena cobrar! Pide dinero a una cuenta nueva de Expensify y recibe $${CONST.REFERRAL_PROGRAM.REVENUE} cuando se conviertan en clientes.`,
},
[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SEND_MONEY]: {
buttonText1: 'Envía dinero, ',
buttonText2: `recibe $${CONST.REFERRAL_PROGRAM.REVENUE}`,
header: `Envía dinero y recibe $${CONST.REFERRAL_PROGRAM.REVENUE}`,
- body: `¡Hay que enviar dinero para ganar dinero! Envía dinero a una cuenta nueva de Expensify y obtiene $${CONST.REFERRAL_PROGRAM.REVENUE} si se convierten en clientes de Expensify.`,
+ body: `¡Hay que enviar dinero para ganar dinero! Envía dinero a una cuenta nueva de Expensify y recibe $${CONST.REFERRAL_PROGRAM.REVENUE} cuando se conviertan en clientes.`,
},
[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND]: {
buttonText1: 'Invita a un amigo y ',
buttonText2: `recibe $${CONST.REFERRAL_PROGRAM.REVENUE}`,
- header: `Invita a un amigo y obtiene $${CONST.REFERRAL_PROGRAM.REVENUE}`,
- body: `Sé el primero en invitar a un amigo (o a cualquier otra persona) a Expensify y obtiene $${CONST.REFERRAL_PROGRAM.REVENUE} si se convierte en cliente de Expensify. Comparte tu enlace de invitación por SMS, email o publícalo en las redes sociales.`,
+ header: `Recibe $${CONST.REFERRAL_PROGRAM.REVENUE}`,
+ body: `Sé el primero en chatear, enviar o pedir dinero, dividir una factura o compartir tu enlace de invitación con un amigo, y recibirás $${CONST.REFERRAL_PROGRAM.REVENUE} cuando se convierta en cliente. También puedes publicar tu enlace de invitación en las redes sociales.`,
},
[CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SHARE_CODE]: {
buttonText1: `Recibe $${CONST.REFERRAL_PROGRAM.REVENUE}`,
- header: `Invita a un amigo y obtiene $${CONST.REFERRAL_PROGRAM.REVENUE}`,
- body: `Sé el primero en invitar a un amigo (o a cualquier otra persona) a Expensify y obtiene $${CONST.REFERRAL_PROGRAM.REVENUE} si se convierte en cliente de Expensify. Comparte tu enlace de invitación por SMS, email o publícalo en las redes sociales.`,
+ header: `Recibe $${CONST.REFERRAL_PROGRAM.REVENUE}`,
+ body: `Sé el primero en chatear, enviar o pedir dinero, dividir una factura o compartir tu enlace de invitación con un amigo, y recibirás $${CONST.REFERRAL_PROGRAM.REVENUE} cuando se convierta en cliente. También puedes publicar tu enlace de invitación en las redes sociales.`,
},
copyReferralLink: 'Copiar enlace de invitación',
},
violations: {
- allTagLevelsRequired: 'dummy.violations.allTagLevelsRequired',
- autoReportedRejectedExpense: 'dummy.violations.autoReportedRejectedExpense',
- billableExpense: 'dummy.violations.billableExpense',
- cashExpenseWithNoReceipt: 'dummy.violations.cashExpenseWithNoReceipt',
- categoryOutOfPolicy: 'dummy.violations.categoryOutOfPolicy',
- conversionSurcharge: 'dummy.violations.conversionSurcharge',
- customUnitOutOfPolicy: 'dummy.violations.customUnitOutOfPolicy',
- duplicatedTransaction: 'dummy.violations.duplicatedTransaction',
- fieldRequired: 'dummy.violations.fieldRequired',
- futureDate: 'dummy.violations.futureDate',
- invoiceMarkup: 'dummy.violations.invoiceMarkup',
- maxAge: 'dummy.violations.maxAge',
- missingCategory: 'dummy.violations.missingCategory',
- missingComment: 'dummy.violations.missingComment',
- missingTag: 'dummy.violations.missingTag',
- modifiedAmount: 'dummy.violations.modifiedAmount',
- modifiedDate: 'dummy.violations.modifiedDate',
- nonExpensiworksExpense: 'dummy.violations.nonExpensiworksExpense',
- overAutoApprovalLimit: 'dummy.violations.overAutoApprovalLimit',
- overCategoryLimit: 'dummy.violations.overCategoryLimit',
- overLimit: 'dummy.violations.overLimit',
- overLimitAttendee: 'dummy.violations.overLimitAttendee',
- perDayLimit: 'dummy.violations.perDayLimit',
- receiptNotSmartScanned: 'dummy.violations.receiptNotSmartScanned',
- receiptRequired: 'dummy.violations.receiptRequired',
- rter: 'dummy.violations.rter',
- smartscanFailed: 'dummy.violations.smartscanFailed',
- someTagLevelsRequired: 'dummy.violations.someTagLevelsRequired',
- tagOutOfPolicy: 'dummy.violations.tagOutOfPolicy',
- taxAmountChanged: 'dummy.violations.taxAmountChanged',
- taxOutOfPolicy: 'dummy.violations.taxOutOfPolicy',
- taxRateChanged: 'dummy.violations.taxRateChanged',
- taxRequired: 'dummy.violations.taxRequired',
+ allTagLevelsRequired: 'Todas las etiquetas son obligatorias',
+ autoReportedRejectedExpense: ({rejectedBy, rejectReason}: ViolationsAutoReportedRejectedExpenseParams) => `${rejectedBy} rechazó la solicitud y comentó "${rejectReason}"`,
+ billableExpense: 'La opción facturable ya no es válida',
+ cashExpenseWithNoReceipt: ({amount}: ViolationsCashExpenseWithNoReceiptParams) => `Recibo obligatorio para montos mayores a ${amount}`,
+ categoryOutOfPolicy: 'La categoría ya no es válida',
+ conversionSurcharge: ({surcharge}: ViolationsConversionSurchargeParams) => `${surcharge}% de recargo aplicado`,
+ customUnitOutOfPolicy: 'Unidad ya no es válida',
+ duplicatedTransaction: 'Potencial duplicado',
+ fieldRequired: 'Los campos del informe son obligatorios',
+ futureDate: 'Fecha futura no permitida',
+ invoiceMarkup: ({invoiceMarkup}: ViolationsInvoiceMarkupParams) => `Incrementado un ${invoiceMarkup}%`,
+ maxAge: ({maxAge}: ViolationsMaxAgeParams) => `Fecha de más de ${maxAge} días`,
+ missingCategory: 'Falta categoría',
+ missingComment: 'Descripción obligatoria para categoría seleccionada',
+ missingTag: ({tagName}: ViolationsMissingTagParams) => `Falta ${tagName}`,
+ modifiedAmount: 'Importe superior al del recibo escaneado',
+ modifiedDate: 'Fecha difiere del recibo escaneado',
+ nonExpensiworksExpense: 'Gasto no es de Expensiworks',
+ overAutoApprovalLimit: ({formattedLimitAmount}: ViolationsOverAutoApprovalLimitParams) => `Importe supera el límite de aprobación automática de ${formattedLimitAmount}`,
+ overCategoryLimit: ({categoryLimit}: ViolationsOverCategoryLimitParams) => `Importe supera el límite para la categoría de ${categoryLimit}/persona`,
+ overLimit: ({amount}: ViolationsOverLimitParams) => `Importe supera el límite de ${amount}/persona`,
+ overLimitAttendee: ({amount}: ViolationsOverLimitParams) => `Importe supera el límite de ${amount}/persona`,
+ perDayLimit: ({limit}: ViolationsPerDayLimitParams) => `Importe supera el límite diario de la categoría de ${limit}/persona`,
+ receiptNotSmartScanned: 'Recibo no verificado. Por favor, confirma su exactitud',
+ receiptRequired: ({amount, category}: ViolationsReceiptRequiredParams) => `Recibo obligatorio para importes sobre ${category ? 'el limite de la categoría de ' : ''}${amount}`,
+ rter: ({brokenBankConnection, isAdmin, email, isTransactionOlderThan7Days, member}: ViolationsRterParams) => {
+ if (brokenBankConnection) {
+ return isAdmin
+ ? `No se puede adjuntar recibo debido a una conexión con su banco que ${email} necesita arreglar`
+ : 'No se puede adjuntar recibo debido a una conexión con su banco que necesitas arreglar';
+ }
+ if (!isTransactionOlderThan7Days) {
+ return isAdmin
+ ? `Pídele a ${member} que marque la transacción como efectivo o espera 7 días e intenta de nuevo`
+ : 'Esperando adjuntar automáticamente a transacción de tarjeta de crédito';
+ }
+ return '';
+ },
+ smartscanFailed: 'No se pudo escanear el recibo. Introduce los datos manualmente',
+ someTagLevelsRequired: 'Falta etiqueta',
+ tagOutOfPolicy: ({tagName}: ViolationsTagOutOfPolicyParams) => `Le etiqueta ${tagName} ya no es válida`,
+ taxAmountChanged: 'El importe del impuesto fue modificado',
+ taxOutOfPolicy: ({taxName}: ViolationsTaxOutOfPolicyParams) => `${taxName} ya no es válido`,
+ taxRateChanged: 'La tasa de impuesto fue modificada',
+ taxRequired: 'Falta tasa de impuesto',
},
} satisfies EnglishTranslation;
diff --git a/src/languages/types.ts b/src/languages/types.ts
index dd2d339858b0..35a5110abf79 100644
--- a/src/languages/types.ts
+++ b/src/languages/types.ts
@@ -74,6 +74,10 @@ type WelcomeToRoomParams = {
roomName: string;
};
+type UsePlusButtonParams = {
+ additionalText: string;
+};
+
type ReportArchiveReasonsClosedParams = {
displayName: string;
};
@@ -131,6 +135,8 @@ type WaitingOnBankAccountParams = {submitterDisplayName: string};
type CanceledRequestParams = {amount: string; submitterDisplayName: string};
+type AdminCanceledRequestParams = {amount: string};
+
type SettledAfterAddedBankAccountParams = {submitterDisplayName: string; amount: string};
type PaidElsewhereWithAmountParams = {payer?: string; amount: string};
@@ -209,6 +215,40 @@ type TagSelectionParams = {tagName: string};
type WalletProgramParams = {walletProgram: string};
+type ViolationsAutoReportedRejectedExpenseParams = {rejectedBy: string; rejectReason: string};
+
+type ViolationsCashExpenseWithNoReceiptParams = {amount: string};
+
+type ViolationsConversionSurchargeParams = {surcharge?: number};
+
+type ViolationsInvoiceMarkupParams = {invoiceMarkup?: number};
+
+type ViolationsMaxAgeParams = {maxAge: number};
+
+type ViolationsMissingTagParams = {tagName?: string};
+
+type ViolationsOverAutoApprovalLimitParams = {formattedLimitAmount: string};
+
+type ViolationsOverCategoryLimitParams = {categoryLimit: string};
+
+type ViolationsOverLimitParams = {amount: string};
+
+type ViolationsPerDayLimitParams = {limit: string};
+
+type ViolationsReceiptRequiredParams = {amount: string; category?: string};
+
+type ViolationsRterParams = {
+ brokenBankConnection: boolean;
+ isAdmin: boolean;
+ email?: string;
+ isTransactionOlderThan7Days: boolean;
+ member?: string;
+};
+
+type ViolationsTagOutOfPolicyParams = {tagName?: string};
+
+type ViolationsTaxOutOfPolicyParams = {taxName?: string};
+
type TaskCreatedActionParams = {title: string};
/* Translation Object types */
@@ -250,87 +290,103 @@ type TranslationFlatObject = {
};
export type {
- TranslationBase,
- TranslationPaths,
- EnglishTranslation,
- TranslationFlatObject,
+ AdminCanceledRequestParams,
+ ApprovedAmountParams,
AddressLineParams,
- CharacterLimitParams,
- MaxParticipantsReachedParams,
- ZipCodeExampleFormatParams,
- LoggedInAsParams,
- NewFaceEnterMagicCodeParams,
- WelcomeEnterMagicCodeParams,
AlreadySignedInParams,
- GoBackMessageParams,
- LocalTimeParams,
- EditActionParams,
- DeleteActionParams,
- DeleteConfirmationParams,
- BeginningOfChatHistoryDomainRoomPartOneParams,
+ AmountEachParams,
BeginningOfChatHistoryAdminRoomPartOneParams,
BeginningOfChatHistoryAnnounceRoomPartOneParams,
BeginningOfChatHistoryAnnounceRoomPartTwo,
- WelcomeToRoomParams,
- ReportArchiveReasonsClosedParams,
- ReportArchiveReasonsMergedParams,
- ReportArchiveReasonsRemovedFromPolicyParams,
- ReportArchiveReasonsPolicyDeletedParams,
- RequestCountParams,
- SettleExpensifyCardParams,
- RequestAmountParams,
- RequestedAmountMessageParams,
- SplitAmountParams,
+ BeginningOfChatHistoryDomainRoomPartOneParams,
+ CanceledRequestParams,
+ CharacterLimitParams,
+ ConfirmThatParams,
+ DateShouldBeAfterParams,
+ DateShouldBeBeforeParams,
+ DeleteActionParams,
+ DeleteConfirmationParams,
DidSplitAmountMessageParams,
- AmountEachParams,
+ EditActionParams,
+ EnglishTranslation,
+ EnterMagicCodeParams,
+ FormattedMaxLengthParams,
+ GoBackMessageParams,
+ GoToRoomParams,
+ IncorrectZipFormatParams,
+ InstantSummaryParams,
+ LocalTimeParams,
+ LoggedInAsParams,
+ ManagerApprovedAmountParams,
+ ManagerApprovedParams,
+ MaxParticipantsReachedParams,
+ NewFaceEnterMagicCodeParams,
+ NoLongerHaveAccessParams,
+ NotAllowedExtensionParams,
+ NotYouParams,
+ OOOEventSummaryFullDayParams,
+ OOOEventSummaryPartialDayParams,
+ OurEmailProviderParams,
+ PaidElsewhereWithAmountParams,
+ PaidWithExpensifyWithAmountParams,
+ ParentNavigationSummaryParams,
PayerOwesAmountParams,
PayerOwesParams,
PayerPaidAmountParams,
PayerPaidParams,
- ApprovedAmountParams,
- ManagerApprovedParams,
- ManagerApprovedAmountParams,
PayerSettledParams,
- WaitingOnBankAccountParams,
- CanceledRequestParams,
- SettledAfterAddedBankAccountParams,
- PaidElsewhereWithAmountParams,
- PaidWithExpensifyWithAmountParams,
- ThreadRequestReportNameParams,
- ThreadSentMoneyReportNameParams,
- SizeExceededParams,
+ RemovedTheRequestParams,
+ RenamedRoomActionParams,
+ ReportArchiveReasonsClosedParams,
+ ReportArchiveReasonsMergedParams,
+ ReportArchiveReasonsPolicyDeletedParams,
+ ReportArchiveReasonsRemovedFromPolicyParams,
+ RequestAmountParams,
+ RequestCountParams,
+ RequestedAmountMessageParams,
ResolutionConstraintsParams,
- NotAllowedExtensionParams,
- EnterMagicCodeParams,
- TransferParams,
- InstantSummaryParams,
- NotYouParams,
- DateShouldBeBeforeParams,
- DateShouldBeAfterParams,
- IncorrectZipFormatParams,
- WeSentYouMagicSignInLinkParams,
- ToValidateLoginParams,
- NoLongerHaveAccessParams,
- OurEmailProviderParams,
- ConfirmThatParams,
- UntilTimeParams,
- StepCounterParams,
- UserIsAlreadyMemberParams,
- GoToRoomParams,
- WelcomeNoteParams,
RoomNameReservedErrorParams,
- RenamedRoomActionParams,
RoomRenamedToParams,
- OOOEventSummaryFullDayParams,
- OOOEventSummaryPartialDayParams,
- ParentNavigationSummaryParams,
+ SetTheDistanceParams,
SetTheRequestParams,
- UpdatedTheRequestParams,
- RemovedTheRequestParams,
- FormattedMaxLengthParams,
+ SettleExpensifyCardParams,
+ SettledAfterAddedBankAccountParams,
+ SizeExceededParams,
+ SplitAmountParams,
+ StepCounterParams,
TagSelectionParams,
- SetTheDistanceParams,
+ TaskCreatedActionParams,
+ ThreadRequestReportNameParams,
+ ThreadSentMoneyReportNameParams,
+ ToValidateLoginParams,
+ TransferParams,
+ TranslationBase,
+ TranslationFlatObject,
+ TranslationPaths,
+ UntilTimeParams,
UpdatedTheDistanceParams,
+ UpdatedTheRequestParams,
+ UserIsAlreadyMemberParams,
+ ViolationsAutoReportedRejectedExpenseParams,
+ ViolationsCashExpenseWithNoReceiptParams,
+ ViolationsConversionSurchargeParams,
+ ViolationsInvoiceMarkupParams,
+ ViolationsMaxAgeParams,
+ ViolationsMissingTagParams,
+ ViolationsOverAutoApprovalLimitParams,
+ ViolationsOverCategoryLimitParams,
+ ViolationsOverLimitParams,
+ ViolationsPerDayLimitParams,
+ ViolationsReceiptRequiredParams,
+ ViolationsRterParams,
+ ViolationsTagOutOfPolicyParams,
+ ViolationsTaxOutOfPolicyParams,
+ WaitingOnBankAccountParams,
WalletProgramParams,
- TaskCreatedActionParams,
+ UsePlusButtonParams,
+ WeSentYouMagicSignInLinkParams,
+ WelcomeEnterMagicCodeParams,
+ WelcomeNoteParams,
+ WelcomeToRoomParams,
+ ZipCodeExampleFormatParams,
};
diff --git a/src/libs/API.ts b/src/libs/API.ts
index d5cfd56cd4af..4305469eafd5 100644
--- a/src/libs/API.ts
+++ b/src/libs/API.ts
@@ -27,7 +27,7 @@ Request.use(Middleware.Reauthentication);
// If an optimistic ID is not used by the server, this will update the remaining serialized requests using that optimistic ID to use the correct ID instead.
Request.use(Middleware.HandleUnusedOptimisticID);
-// SaveResponseInOnyx - Merges either the successData or failureData into Onyx depending on if the call was successful or not. This needs to be the LAST middleware we use, don't add any
+// SaveResponseInOnyx - Merges either the successData or failureData (or finallyData, if included in place of the former two values) into Onyx depending on if the call was successful or not. This needs to be the LAST middleware we use, don't add any
// middlewares after this, because the SequentialQueue depends on the result of this middleware to pause the queue (if needed) to bring the app to an up-to-date state.
Request.use(Middleware.SaveResponseInOnyx);
@@ -35,12 +35,13 @@ type OnyxData = {
optimisticData?: OnyxUpdate[];
successData?: OnyxUpdate[];
failureData?: OnyxUpdate[];
+ finallyData?: OnyxUpdate[];
};
type ApiRequestType = ValueOf;
/**
- * All calls to API.write() will be persisted to disk as JSON with the params, successData, and failureData.
+ * All calls to API.write() will be persisted to disk as JSON with the params, successData, and failureData (or finallyData, if included in place of the former two values).
* This is so that if the network is unavailable or the app is closed, we can send the WRITE request later.
*
* @param command - Name of API command to call.
@@ -51,6 +52,7 @@ type ApiRequestType = ValueOf;
* @param [onyxData.optimisticData] - Onyx instructions that will be passed to Onyx.update() before the request is made.
* @param [onyxData.successData] - Onyx instructions that will be passed to Onyx.update() when the response has jsonCode === 200.
* @param [onyxData.failureData] - Onyx instructions that will be passed to Onyx.update() when the response has jsonCode !== 200.
+ * @param [onyxData.finallyData] - Onyx instructions that will be passed to Onyx.update() when the response has jsonCode === 200 or jsonCode !== 200.
*/
function write(command: string, apiCommandParameters: Record = {}, onyxData: OnyxData = {}) {
Log.info('Called API write', false, {command, ...apiCommandParameters});
@@ -105,6 +107,7 @@ function write(command: string, apiCommandParameters: Record =
* @param [onyxData.optimisticData] - Onyx instructions that will be passed to Onyx.update() before the request is made.
* @param [onyxData.successData] - Onyx instructions that will be passed to Onyx.update() when the response has jsonCode === 200.
* @param [onyxData.failureData] - Onyx instructions that will be passed to Onyx.update() when the response has jsonCode !== 200.
+ * @param [onyxData.finallyData] - Onyx instructions that will be passed to Onyx.update() when the response has jsonCode === 200 or jsonCode !== 200.
* @param [apiRequestType] - Can be either 'read', 'write', or 'makeRequestWithSideEffects'. We use this to either return the chained
* response back to the caller or to trigger reconnection callbacks when re-authentication is required.
* @returns
@@ -152,6 +155,7 @@ function makeRequestWithSideEffects(
* @param [onyxData.optimisticData] - Onyx instructions that will be passed to Onyx.update() before the request is made.
* @param [onyxData.successData] - Onyx instructions that will be passed to Onyx.update() when the response has jsonCode === 200.
* @param [onyxData.failureData] - Onyx instructions that will be passed to Onyx.update() when the response has jsonCode !== 200.
+ * @param [onyxData.finallyData] - Onyx instructions that will be passed to Onyx.update() when the response has jsonCode === 200 or jsonCode !== 200.
*/
function read(command: string, apiCommandParameters: Record, onyxData: OnyxData = {}) {
// Ensure all write requests on the sequential queue have finished responding before running read requests.
diff --git a/src/libs/BrickRoadsUtils.ts b/src/libs/BrickRoadsUtils.ts
new file mode 100644
index 000000000000..db7cc40a7940
--- /dev/null
+++ b/src/libs/BrickRoadsUtils.ts
@@ -0,0 +1,74 @@
+import type {OnyxCollection} from 'react-native-onyx';
+import Onyx from 'react-native-onyx';
+import type {ValueOf} from 'type-fest';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import type {Report} from '@src/types/onyx';
+import * as OptionsListUtils from './OptionsListUtils';
+import * as ReportActionsUtils from './ReportActionsUtils';
+import * as ReportUtils from './ReportUtils';
+
+let allReports: OnyxCollection;
+
+type BrickRoad = ValueOf | undefined;
+
+Onyx.connect({
+ key: ONYXKEYS.COLLECTION.REPORT,
+ waitForCollectionCallback: true,
+ callback: (value) => (allReports = value),
+});
+
+/**
+ * @param report
+ * @returns BrickRoad for the policy passed as a param
+ */
+const getBrickRoadForPolicy = (report: Report): BrickRoad => {
+ const reportActions = ReportActionsUtils.getAllReportActions(report.reportID);
+ const reportErrors = OptionsListUtils.getAllReportErrors(report, reportActions);
+ const doesReportContainErrors = Object.keys(reportErrors ?? {}).length !== 0 ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined;
+ if (doesReportContainErrors) {
+ return CONST.BRICK_ROAD.RBR;
+ }
+
+ // To determine if the report requires attention from the current user, we need to load the parent report action
+ let itemParentReportAction = {};
+ if (report.parentReportID) {
+ const itemParentReportActions = ReportActionsUtils.getAllReportActions(report.parentReportID);
+ itemParentReportAction = report.parentReportActionID ? itemParentReportActions[report.parentReportActionID] : {};
+ }
+ const reportOption = {...report, isUnread: ReportUtils.isUnread(report), isUnreadWithMention: ReportUtils.isUnreadWithMention(report)};
+ const shouldShowGreenDotIndicator = ReportUtils.requiresAttentionFromCurrentUser(reportOption, itemParentReportAction);
+ return shouldShowGreenDotIndicator ? CONST.BRICK_ROAD.GBR : undefined;
+};
+
+/**
+ * @returns a map where the keys are policyIDs and the values are BrickRoads for each policy
+ */
+function getWorkspacesBrickRoads(): Record {
+ if (!allReports) {
+ return {};
+ }
+
+ // The key in this map is the workspace id
+ const workspacesBrickRoadsMap: Record = {};
+
+ Object.keys(allReports).forEach((report) => {
+ const policyID = allReports?.[report]?.policyID;
+ const policyReport = allReports ? allReports[report] : null;
+ if (!policyID || !policyReport || workspacesBrickRoadsMap[policyID] === CONST.BRICK_ROAD.RBR) {
+ return;
+ }
+ const workspaceBrickRoad = getBrickRoadForPolicy(policyReport);
+
+ if (!workspaceBrickRoad && !!workspacesBrickRoadsMap[policyID]) {
+ return;
+ }
+
+ workspacesBrickRoadsMap[policyID] = workspaceBrickRoad;
+ });
+
+ return workspacesBrickRoadsMap;
+}
+
+export {getBrickRoadForPolicy, getWorkspacesBrickRoads};
+export type {BrickRoad};
diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts
index 08f61a50b645..1a10eb03a00e 100644
--- a/src/libs/DateUtils.ts
+++ b/src/libs/DateUtils.ts
@@ -30,6 +30,7 @@ import Onyx from 'react-native-onyx';
import type {ValueOf} from 'type-fest';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
+import {timezoneBackwardMap} from '@src/TIMEZONES';
import type {SelectedTimezone, Timezone} from '@src/types/onyx/PersonalDetails';
import * as CurrentDate from './actions/CurrentDate';
import * as Localize from './Localize';
@@ -70,6 +71,12 @@ Onyx.connect({
},
});
+let networkTimeSkew = 0;
+Onyx.connect({
+ key: ONYXKEYS.NETWORK,
+ callback: (value) => (networkTimeSkew = value?.timeSkew ?? 0),
+});
+
/**
* Get the day of the week that the week starts on
*/
@@ -358,6 +365,16 @@ function getDBTime(timestamp: string | number = ''): string {
return datetime.toISOString().replace('T', ' ').replace('Z', '');
}
+/**
+ * Returns the current time plus skew in milliseconds in the format expected by the database
+ */
+function getDBTimeWithSkew(): string {
+ if (networkTimeSkew > 0) {
+ return getDBTime(new Date().valueOf() + networkTimeSkew);
+ }
+ return getDBTime();
+}
+
function subtractMillisecondsFromDateTime(dateTime: string, milliseconds: number): string {
const date = zonedTimeToUtc(dateTime, 'UTC');
const newTimestamp = subMilliseconds(date, milliseconds).valueOf();
@@ -697,6 +714,22 @@ function formatWithUTCTimeZone(datetime: string, dateFormat: string = CONST.DATE
return '';
}
+/**
+ *
+ * @param timezone
+ * function format unsupported timezone to supported timezone
+ * @returns Timezone
+ */
+function formatToSupportedTimezone(timezoneInput: Timezone): Timezone {
+ if (!timezoneInput?.selected) {
+ return timezoneInput;
+ }
+ return {
+ selected: timezoneBackwardMap[timezoneInput.selected] ?? timezoneInput.selected,
+ automatic: timezoneInput.automatic,
+ };
+}
+
const DateUtils = {
formatToDayOfWeek,
formatToLongDateWithWeekday,
@@ -711,6 +744,7 @@ const DateUtils = {
setTimezoneUpdated,
getMicroseconds,
getDBTime,
+ getDBTimeWithSkew,
setLocale,
subtractMillisecondsFromDateTime,
getDateStringFromISOTimestamp,
@@ -739,6 +773,7 @@ const DateUtils = {
getWeekStartsOn,
getWeekEndsOn,
isTimeAtLeastOneMinuteInFuture,
+ formatToSupportedTimezone,
};
export default DateUtils;
diff --git a/src/libs/DoInteractionTask/index.desktop.ts b/src/libs/DoInteractionTask/index.desktop.ts
new file mode 100644
index 000000000000..73b3cb19ec32
--- /dev/null
+++ b/src/libs/DoInteractionTask/index.desktop.ts
@@ -0,0 +1,10 @@
+import {InteractionManager} from 'react-native';
+
+// For desktop, we should call the callback after all interactions to prevent freezing. See more detail in https://github.com/Expensify/App/issues/28916
+function doInteractionTask(callback: () => void) {
+ return InteractionManager.runAfterInteractions(() => {
+ callback();
+ });
+}
+
+export default doInteractionTask;
diff --git a/src/libs/DoInteractionTask/index.ts b/src/libs/DoInteractionTask/index.ts
new file mode 100644
index 000000000000..dffbb0562b98
--- /dev/null
+++ b/src/libs/DoInteractionTask/index.ts
@@ -0,0 +1,6 @@
+function doInteractionTask(callback: () => void) {
+ callback();
+ return null;
+}
+
+export default doInteractionTask;
diff --git a/src/libs/EmojiTrie.ts b/src/libs/EmojiTrie.ts
index 4c441facdd46..d0f0b0dcfab6 100644
--- a/src/libs/EmojiTrie.ts
+++ b/src/libs/EmojiTrie.ts
@@ -1,38 +1,11 @@
import emojis, {localeEmojis} from '@assets/emojis';
+import type {Emoji, HeaderEmoji, PickerEmoji} from '@assets/emojis/types';
import CONST from '@src/CONST';
-import type IconAsset from '@src/types/utils/IconAsset';
import Timing from './actions/Timing';
import Trie from './Trie';
-type HeaderEmoji = {
- code: string;
- header: boolean;
- icon: IconAsset;
-};
-
-type SimpleEmoji = {
- code: string;
- name: string;
- types?: string[];
-};
-
-type Emoji = HeaderEmoji | SimpleEmoji;
-
-type LocalizedEmoji = {
- name?: string;
- keywords: string[];
-};
-
-type LocalizedEmojis = Record;
-
-type Suggestion = {
- code: string;
- types?: string[];
- name: string;
-};
-
type EmojiMetaData = {
- suggestions?: Suggestion[];
+ suggestions?: Emoji[];
code?: string;
types?: string[];
name?: string;
@@ -56,7 +29,7 @@ type EmojiTrie = {
* @param name The localized name of the emoji.
* @param shouldPrependKeyword Prepend the keyword (instead of append) to the suggestions
*/
-function addKeywordsToTrie(trie: Trie, keywords: string[], item: SimpleEmoji, name: string, shouldPrependKeyword = false) {
+function addKeywordsToTrie(trie: Trie, keywords: string[], item: Emoji, name: string, shouldPrependKeyword = false) {
keywords.forEach((keyword) => {
const keywordNode = trie.search(keyword);
if (!keywordNode) {
@@ -85,13 +58,13 @@ function getNameParts(name: string): string[] {
function createTrie(lang: SupportedLanguage = CONST.LOCALES.DEFAULT): Trie {
const trie = new Trie();
- const langEmojis: LocalizedEmojis = localeEmojis[lang];
- const defaultLangEmojis: LocalizedEmojis = localeEmojis[CONST.LOCALES.DEFAULT];
+ const langEmojis = localeEmojis[lang];
+ const defaultLangEmojis = localeEmojis[CONST.LOCALES.DEFAULT];
const isDefaultLocale = lang === CONST.LOCALES.DEFAULT;
emojis
- .filter((item: Emoji): item is SimpleEmoji => !(item as HeaderEmoji).header)
- .forEach((item: SimpleEmoji) => {
+ .filter((item: PickerEmoji): item is Emoji => !(item as HeaderEmoji).header)
+ .forEach((item: Emoji) => {
const englishName = item.name;
const localeName = langEmojis?.[item.code]?.name ?? englishName;
@@ -127,4 +100,4 @@ const emojiTrie: EmojiTrie = supportedLanguages.reduce((prev, cur) => ({...prev,
Timing.end(CONST.TIMING.TRIE_INITIALIZATION);
export default emojiTrie;
-export type {SimpleEmoji, SupportedLanguage};
+export type {SupportedLanguage};
diff --git a/src/libs/EmojiUtils.ts b/src/libs/EmojiUtils.ts
index 06bbd5c871ed..e34fa0b90fc6 100644
--- a/src/libs/EmojiUtils.ts
+++ b/src/libs/EmojiUtils.ts
@@ -2,11 +2,12 @@ import {getUnixTime} from 'date-fns';
import Str from 'expensify-common/lib/str';
import memoize from 'lodash/memoize';
import Onyx from 'react-native-onyx';
+import type {OnyxEntry} from 'react-native-onyx';
import * as Emojis from '@assets/emojis';
import type {Emoji, HeaderEmoji, PickerEmojis} from '@assets/emojis/types';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
-import type {FrequentlyUsedEmoji} from '@src/types/onyx';
+import type {FrequentlyUsedEmoji, Locale} from '@src/types/onyx';
import type {ReportActionReaction, UsersReactions} from '@src/types/onyx/ReportActionReactions';
import type IconAsset from '@src/types/utils/IconAsset';
import type {SupportedLanguage} from './EmojiTrie';
@@ -48,13 +49,13 @@ const getEmojiName = (emoji: Emoji, lang: 'en' | 'es' = CONST.LOCALES.DEFAULT):
/**
* Given an English emoji name, get its localized version
*/
-const getLocalizedEmojiName = (name: string, lang: 'en' | 'es'): string => {
+const getLocalizedEmojiName = (name: string, lang: OnyxEntry): string => {
if (lang === CONST.LOCALES.DEFAULT) {
return name;
}
const emojiCode = Emojis.emojiNameTable[name]?.code ?? '';
- return Emojis.localeEmojis[lang]?.[emojiCode]?.name ?? '';
+ return (lang && Emojis.localeEmojis[lang]?.[emojiCode]?.name) ?? '';
};
/**
@@ -305,7 +306,7 @@ function getAddedEmojis(currentEmojis: Emoji[], formerEmojis: Emoji[]): Emoji[]
* Replace any emoji name in a text with the emoji icon.
* If we're on mobile, we also add a space after the emoji granted there's no text after it.
*/
-function replaceEmojis(text: string, preferredSkinTone = CONST.EMOJI_DEFAULT_SKIN_TONE, lang: 'en' | 'es' = CONST.LOCALES.DEFAULT): ReplacedEmoji {
+function replaceEmojis(text: string, preferredSkinTone: number = CONST.EMOJI_DEFAULT_SKIN_TONE, lang: Locale = CONST.LOCALES.DEFAULT): ReplacedEmoji {
// emojisTrie is importing the emoji JSON file on the app starting and we want to avoid it
const emojisTrie = require('./EmojiTrie').default;
@@ -369,7 +370,7 @@ function replaceEmojis(text: string, preferredSkinTone = CONST.EMOJI_DEFAULT_SKI
/**
* Find all emojis in a text and replace them with their code.
*/
-function replaceAndExtractEmojis(text: string, preferredSkinTone = CONST.EMOJI_DEFAULT_SKIN_TONE, lang = CONST.LOCALES.DEFAULT): ReplacedEmoji {
+function replaceAndExtractEmojis(text: string, preferredSkinTone: number = CONST.EMOJI_DEFAULT_SKIN_TONE, lang: Locale = CONST.LOCALES.DEFAULT): ReplacedEmoji {
const {text: convertedText = '', emojis = [], cursorPosition} = replaceEmojis(text, preferredSkinTone, lang);
return {
@@ -438,8 +439,8 @@ const getPreferredSkinToneIndex = (value: string | number | null): number => {
* Given an emoji object it returns the correct emoji code
* based on the users preferred skin tone.
*/
-const getPreferredEmojiCode = (emoji: Emoji, preferredSkinTone: number): string => {
- if (emoji.types) {
+const getPreferredEmojiCode = (emoji: Emoji, preferredSkinTone: OnyxEntry): string => {
+ if (emoji.types && typeof preferredSkinTone === 'number') {
const emojiCodeWithSkinTone = emoji.types[preferredSkinTone];
// Note: it can happen that preferredSkinTone has a outdated format,
diff --git a/src/libs/GetPhysicalCardUtils.ts b/src/libs/GetPhysicalCardUtils.ts
index eebefd7c1d52..139297a26513 100644
--- a/src/libs/GetPhysicalCardUtils.ts
+++ b/src/libs/GetPhysicalCardUtils.ts
@@ -116,7 +116,7 @@ function getUpdatedDraftValues(draftValues: DraftValues, privatePersonalDetails:
* @param draftValues
* @returns
*/
-function getUpdatedPrivatePersonalDetails(draftValues: DraftValues) {
+function getUpdatedPrivatePersonalDetails(draftValues: DraftValues): PrivatePersonalDetails {
const {addressLine1, addressLine2, city, country, legalFirstName, legalLastName, phoneNumber, state, zipPostCode} = draftValues;
return {
legalFirstName,
@@ -127,3 +127,4 @@ function getUpdatedPrivatePersonalDetails(draftValues: DraftValues) {
}
export {getUpdatedDraftValues, getUpdatedPrivatePersonalDetails, goToNextPhysicalCardRoute, setCurrentRoute};
+export type {PrivatePersonalDetails};
diff --git a/src/libs/GroupChatUtils.ts b/src/libs/GroupChatUtils.ts
index ba14bc9c9c3d..26b3665ca4ce 100644
--- a/src/libs/GroupChatUtils.ts
+++ b/src/libs/GroupChatUtils.ts
@@ -1,26 +1,18 @@
-import type {OnyxEntry} from 'react-native-onyx';
-import Onyx from 'react-native-onyx';
-import ONYXKEYS from '@src/ONYXKEYS';
-import type {PersonalDetailsList, Report} from '@src/types/onyx';
-import * as OptionsListUtils from './OptionsListUtils';
+import type {Report} from '@src/types/onyx';
import * as ReportUtils from './ReportUtils';
-let allPersonalDetails: OnyxEntry = {};
-Onyx.connect({
- key: ONYXKEYS.PERSONAL_DETAILS_LIST,
- callback: (val) => (allPersonalDetails = val),
-});
-
/**
* Returns the report name if the report is a group chat
*/
function getGroupChatName(report: Report): string | undefined {
const participants = report.participantAccountIDs ?? [];
const isMultipleParticipantReport = participants.length > 1;
- const participantPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs(participants, allPersonalDetails ?? {});
- // @ts-expect-error Error will gone when OptionsListUtils will be migrated to Typescript
- const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips(participantPersonalDetails, isMultipleParticipantReport);
- return ReportUtils.getDisplayNamesStringFromTooltips(displayNamesWithTooltips);
+
+ return participants
+ .map((participant) => ReportUtils.getDisplayNameForParticipant(participant, isMultipleParticipantReport))
+ .sort((first, second) => first?.localeCompare(second ?? '') ?? 0)
+ .filter(Boolean)
+ .join(', ');
}
export {
diff --git a/src/libs/HttpUtils.ts b/src/libs/HttpUtils.ts
index e40c8148c923..22e342ac847b 100644
--- a/src/libs/HttpUtils.ts
+++ b/src/libs/HttpUtils.ts
@@ -5,6 +5,7 @@ import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {RequestType} from '@src/types/onyx/Request';
import type Response from '@src/types/onyx/Response';
+import * as NetworkActions from './actions/Network';
import * as ApiUtils from './ApiUtils';
import HttpsError from './Errors/HttpsError';
@@ -25,17 +26,41 @@ Onyx.connect({
// We use the AbortController API to terminate pending request in `cancelPendingRequests`
let cancellationController = new AbortController();
+/**
+ * The API commands that require the skew calculation
+ */
+const addSkewList = ['OpenReport', 'ReconnectApp', 'OpenApp'];
+
+/**
+ * Regex to get API command from the command
+ */
+const APICommandRegex = /[?&]command=([^&]+)/;
+
/**
* Send an HTTP request, and attempt to resolve the json response.
* If there is a network error, we'll set the application offline.
*/
function processHTTPRequest(url: string, method: RequestType = 'get', body: FormData | null = null, canCancel = true): Promise {
+ const startTime = new Date().valueOf();
return fetch(url, {
// We hook requests to the same Controller signal, so we can cancel them all at once
signal: canCancel ? cancellationController.signal : undefined,
method,
body,
})
+ .then((response) => {
+ // We are calculating the skew to minimize the delay when posting the messages
+ const match = url.match(APICommandRegex)?.[1];
+ if (match && addSkewList.includes(match) && response.headers) {
+ const dateHeaderValue = response.headers.get('Date');
+ const serverTime = dateHeaderValue ? new Date(dateHeaderValue).valueOf() : new Date().valueOf();
+ const endTime = new Date().valueOf();
+ const latency = (endTime - startTime) / 2;
+ const skew = serverTime - startTime + latency;
+ NetworkActions.setTimeSkew(dateHeaderValue ? skew : 0);
+ }
+ return response;
+ })
.then((response) => {
// Test mode where all requests will succeed in the server, but fail to return a response
if (shouldFailAllRequests || shouldForceOffline) {
diff --git a/src/libs/IOUUtils.ts b/src/libs/IOUUtils.ts
index 09cdfd15cbba..11dd0f5badda 100644
--- a/src/libs/IOUUtils.ts
+++ b/src/libs/IOUUtils.ts
@@ -3,6 +3,7 @@ import type {ValueOf} from 'type-fest';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';
import type {Report, Transaction} from '@src/types/onyx';
+import * as IOU from './actions/IOU';
import * as CurrencyUtils from './CurrencyUtils';
import * as FileUtils from './fileDownload/FileUtils';
import Navigation from './Navigation/Navigation';
@@ -38,7 +39,14 @@ function navigateToStartStepIfScanFileCannotBeRead(
return;
}
- const onFailure = () => navigateToStartMoneyRequestStep(requestType, iouType, transactionID, reportID);
+ const onFailure = () => {
+ IOU.setMoneyRequestReceipt(transactionID, '', '', true);
+ if (requestType === CONST.IOU.REQUEST_TYPE.MANUAL) {
+ Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_SCAN.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID, Navigation.getActiveRouteWithoutParams()));
+ return;
+ }
+ navigateToStartMoneyRequestStep(requestType, iouType, transactionID, reportID);
+ };
FileUtils.readFileAsync(receiptPath, receiptFilename, onSuccess, onFailure);
}
@@ -82,19 +90,20 @@ function updateIOUOwnerAndTotal(iouReport: OnyxEntry, actorAccountID: nu
// Make a copy so we don't mutate the original object
const iouReportUpdate: Report = {...iouReport};
- if (iouReportUpdate.total) {
- if (actorAccountID === iouReport.ownerAccountID) {
- iouReportUpdate.total += isDeleting ? -amount : amount;
- } else {
- iouReportUpdate.total += isDeleting ? amount : -amount;
- }
+ // Let us ensure a valid value before updating the total amount.
+ iouReportUpdate.total = iouReportUpdate.total ?? 0;
- if (iouReportUpdate.total < 0) {
- // The total sign has changed and hence we need to flip the manager and owner of the report.
- iouReportUpdate.ownerAccountID = iouReport.managerID;
- iouReportUpdate.managerID = iouReport.ownerAccountID;
- iouReportUpdate.total = -iouReportUpdate.total;
- }
+ if (actorAccountID === iouReport.ownerAccountID) {
+ iouReportUpdate.total += isDeleting ? -amount : amount;
+ } else {
+ iouReportUpdate.total += isDeleting ? amount : -amount;
+ }
+
+ if (iouReportUpdate.total < 0) {
+ // The total sign has changed and hence we need to flip the manager and owner of the report.
+ iouReportUpdate.ownerAccountID = iouReport.managerID;
+ iouReportUpdate.managerID = iouReport.ownerAccountID;
+ iouReportUpdate.total = -iouReportUpdate.total;
}
return iouReportUpdate;
diff --git a/src/libs/IntlPolyfill/index.native.ts b/src/libs/IntlPolyfill/index.native.ts
index 0819479b50ec..ca1c8f4c250e 100644
--- a/src/libs/IntlPolyfill/index.native.ts
+++ b/src/libs/IntlPolyfill/index.native.ts
@@ -1,3 +1,4 @@
+import polyfillDateTimeFormat from './polyfillDateTimeFormat';
import polyfillListFormat from './polyfillListFormat';
import polyfillNumberFormat from './polyfillNumberFormat';
import type IntlPolyfill from './types';
@@ -10,8 +11,8 @@ const intlPolyfill: IntlPolyfill = () => {
require('@formatjs/intl-getcanonicallocales/polyfill');
require('@formatjs/intl-locale/polyfill');
require('@formatjs/intl-pluralrules/polyfill');
- require('@formatjs/intl-datetimeformat');
polyfillNumberFormat();
+ polyfillDateTimeFormat();
polyfillListFormat();
};
diff --git a/src/libs/IntlPolyfill/index.ts b/src/libs/IntlPolyfill/index.ts
index 42664477409f..4f05fdbefd51 100644
--- a/src/libs/IntlPolyfill/index.ts
+++ b/src/libs/IntlPolyfill/index.ts
@@ -1,3 +1,4 @@
+import polyfillDateTimeFormat from './polyfillDateTimeFormat';
import polyfillNumberFormat from './polyfillNumberFormat';
import type IntlPolyfill from './types';
@@ -6,8 +7,7 @@ import type IntlPolyfill from './types';
* This ensures that the currency data is consistent across platforms and browsers.
*/
const intlPolyfill: IntlPolyfill = () => {
- // Just need to polyfill Intl.NumberFormat for web based platforms
polyfillNumberFormat();
- require('@formatjs/intl-datetimeformat');
+ polyfillDateTimeFormat();
};
export default intlPolyfill;
diff --git a/src/libs/IntlPolyfill/polyfillDateTimeFormat.ts b/src/libs/IntlPolyfill/polyfillDateTimeFormat.ts
new file mode 100644
index 000000000000..13eaaabbd8f4
--- /dev/null
+++ b/src/libs/IntlPolyfill/polyfillDateTimeFormat.ts
@@ -0,0 +1,42 @@
+import type {DateTimeFormatConstructor} from '@formatjs/intl-datetimeformat';
+import DateUtils from '@libs/DateUtils';
+
+/* eslint-disable @typescript-eslint/naming-convention */
+const tzLinks: Record = {
+ 'Africa/Abidjan': 'Africa/Accra',
+ CET: 'Europe/Paris',
+ CST6CDT: 'America/Chicago',
+ EET: 'Europe/Sofia',
+ EST: 'America/Cancun',
+ EST5EDT: 'America/New_York',
+ 'Etc/GMT': 'UTC',
+ 'Etc/UTC': 'UTC',
+ Factory: 'UTC',
+ GMT: 'UTC',
+ HST: 'Pacific/Honolulu',
+ MET: 'Europe/Paris',
+ MST: 'America/Phoenix',
+ MST7MDT: 'America/Denver',
+ PST8PDT: 'America/Los_Angeles',
+ WET: 'Europe/Lisbon',
+};
+/* eslint-enable @typescript-eslint/naming-convention */
+
+export default function () {
+ // Because JS Engines do not expose default timezone, the polyfill cannot detect local timezone that a browser is in.
+ // We must manually do this by getting the local timezone before adding polyfill.
+ let currentTimezone = DateUtils.getCurrentTimezone().selected as string;
+ if (currentTimezone in tzLinks) {
+ currentTimezone = tzLinks[currentTimezone];
+ }
+
+ require('@formatjs/intl-datetimeformat/polyfill-force');
+ require('@formatjs/intl-datetimeformat/locale-data/en');
+ require('@formatjs/intl-datetimeformat/locale-data/es');
+ require('@formatjs/intl-datetimeformat/add-all-tz');
+
+ if ('__setDefaultTimeZone' in Intl.DateTimeFormat) {
+ // eslint-disable-next-line no-underscore-dangle
+ (Intl.DateTimeFormat as DateTimeFormatConstructor).__setDefaultTimeZone(currentTimezone);
+ }
+}
diff --git a/src/libs/LocalePhoneNumber.ts b/src/libs/LocalePhoneNumber.ts
index e50f3be87c84..933aa7937560 100644
--- a/src/libs/LocalePhoneNumber.ts
+++ b/src/libs/LocalePhoneNumber.ts
@@ -1,7 +1,7 @@
-import {parsePhoneNumber} from 'awesome-phonenumber';
import Str from 'expensify-common/lib/str';
import Onyx from 'react-native-onyx';
import ONYXKEYS from '@src/ONYXKEYS';
+import {parsePhoneNumber} from './PhoneNumber';
let countryCodeByIP: number;
Onyx.connect({
diff --git a/src/libs/LoginUtils.ts b/src/libs/LoginUtils.ts
index 742f9bfe16ce..dca84b9b11e0 100644
--- a/src/libs/LoginUtils.ts
+++ b/src/libs/LoginUtils.ts
@@ -1,9 +1,9 @@
-import {parsePhoneNumber} from 'awesome-phonenumber';
import {PUBLIC_DOMAINS} from 'expensify-common/lib/CONST';
import Str from 'expensify-common/lib/str';
import Onyx from 'react-native-onyx';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
+import {parsePhoneNumber} from './PhoneNumber';
let countryCodeByIP: number;
Onyx.connect({
diff --git a/src/libs/Middleware/SaveResponseInOnyx.ts b/src/libs/Middleware/SaveResponseInOnyx.ts
index 9ed93c4ce393..a9182745098b 100644
--- a/src/libs/Middleware/SaveResponseInOnyx.ts
+++ b/src/libs/Middleware/SaveResponseInOnyx.ts
@@ -12,9 +12,9 @@ const SaveResponseInOnyx: Middleware = (requestResponse, request) =>
requestResponse.then((response = {}) => {
const onyxUpdates = response?.onyxData ?? [];
- // Sometimes we call requests that are successfull but they don't have any response or any success/failure data to set. Let's return early since
+ // Sometimes we call requests that are successfull but they don't have any response or any success/failure/finally data to set. Let's return early since
// we don't need to store anything here.
- if (!onyxUpdates && !request.successData && !request.failureData) {
+ if (!onyxUpdates && !request.successData && !request.failureData && !request.finallyData) {
return Promise.resolve(response);
}
diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts
index 600cfb48a1c1..ff5ad9327191 100644
--- a/src/libs/ModifiedExpenseMessage.ts
+++ b/src/libs/ModifiedExpenseMessage.ts
@@ -1,9 +1,9 @@
-import {format} from 'date-fns';
import Onyx from 'react-native-onyx';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {PolicyTags, ReportAction} from '@src/types/onyx';
import * as CurrencyUtils from './CurrencyUtils';
+import DateUtils from './DateUtils';
import * as Localize from './Localize';
import * as PolicyUtils from './PolicyUtils';
import * as ReportUtils from './ReportUtils';
@@ -38,8 +38,10 @@ function buildMessageFragmentForValue(
const newValueToDisplay = valueInQuotes ? `"${newValue}"` : newValue;
const oldValueToDisplay = valueInQuotes ? `"${oldValue}"` : oldValue;
const displayValueName = shouldConvertToLowercase ? valueName.toLowerCase() : valueName;
+ const isOldValuePartialMerchant = valueName === Localize.translateLocal('common.merchant') && oldValue === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT;
- if (!oldValue) {
+ // In case of a partial merchant value, we want to avoid user seeing the "(none)" value in the message.
+ if (!oldValue || isOldValuePartialMerchant) {
const fragment = Localize.translateLocal('iou.setTheRequest', {valueName: displayValueName, newValueToDisplay});
setFragments.push(fragment);
} else if (!newValue) {
@@ -143,13 +145,11 @@ function getForReportAction(reportAction: ReportAction): string {
);
}
- const hasModifiedCreated = reportActionOriginalMessage && 'oldCreated' in reportActionOriginalMessage && 'created' in reportActionOriginalMessage;
- if (hasModifiedCreated) {
- // Take only the YYYY-MM-DD value as the original date includes timestamp
- let formattedOldCreated: Date | string = new Date(reportActionOriginalMessage?.oldCreated ? reportActionOriginalMessage.oldCreated : 0);
- formattedOldCreated = format(formattedOldCreated, CONST.DATE.FNS_FORMAT_STRING);
+ if (reportActionOriginalMessage?.oldCreated && reportActionOriginalMessage?.created) {
+ const formattedOldCreated = DateUtils.formatWithUTCTimeZone(reportActionOriginalMessage.oldCreated, CONST.DATE.FNS_FORMAT_STRING);
+
buildMessageFragmentForValue(
- reportActionOriginalMessage?.created ?? '',
+ reportActionOriginalMessage.created,
formattedOldCreated,
Localize.translateLocal('common.date'),
false,
diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx
index 58825ae6f2b1..03a3612d4566 100644
--- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx
+++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx
@@ -2,6 +2,7 @@ import React, {memo, useEffect, useRef} from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import Onyx, {withOnyx} from 'react-native-onyx';
+import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import KeyboardShortcut from '@libs/KeyboardShortcut';
@@ -50,7 +51,7 @@ type AuthScreensProps = {
isUsingMemoryOnlyKeys: OnyxEntry;
/** The last Onyx update ID was applied to the client */
- lastUpdateIDAppliedToClient: OnyxEntry;
+ initialLastUpdateIDAppliedToClient: OnyxEntry;
};
const loadReportAttachments = () => require('../../../pages/home/report/ReportAttachments').default as React.ComponentType;
@@ -62,6 +63,7 @@ const loadConciergePage = () => require('../../../pages/ConciergePage').default
let timezone: Timezone | null;
let currentAccountID = -1;
let isLoadingApp = false;
+let lastUpdateIDAppliedToClient: OnyxEntry;
Onyx.connect({
key: ONYXKEYS.SESSION,
@@ -111,6 +113,21 @@ Onyx.connect({
},
});
+Onyx.connect({
+ key: ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT,
+ callback: (value: OnyxEntry) => {
+ lastUpdateIDAppliedToClient = value;
+ },
+});
+
+function handleNetworkReconnect() {
+ if (isLoadingApp) {
+ App.openApp();
+ } else {
+ App.reconnectApp(lastUpdateIDAppliedToClient);
+ }
+}
+
const RootStack = createCustomStackNavigator();
// We want to delay the re-rendering for components(e.g. ReportActionCompose)
// that depends on modal visibility until Modal is completely closed and its focused
@@ -128,10 +145,11 @@ const modalScreenListeners = {
},
};
-function AuthScreens({lastUpdateIDAppliedToClient, session, lastOpenedPublicRoomID, isUsingMemoryOnlyKeys = false}: AuthScreensProps) {
+function AuthScreens({session, lastOpenedPublicRoomID, isUsingMemoryOnlyKeys = false, initialLastUpdateIDAppliedToClient}: AuthScreensProps) {
const styles = useThemeStyles();
+ const StyleUtils = useStyleUtils();
const {isSmallScreenWidth} = useWindowDimensions();
- const screenOptions = getRootNavigatorScreenOptions(isSmallScreenWidth, styles);
+ const screenOptions = getRootNavigatorScreenOptions(isSmallScreenWidth, styles, StyleUtils);
const isInitialRender = useRef(true);
if (isInitialRender.current) {
@@ -154,13 +172,7 @@ function AuthScreens({lastUpdateIDAppliedToClient, session, lastOpenedPublicRoom
}
NetworkConnection.listenForReconnect();
- NetworkConnection.onReconnect(() => {
- if (isLoadingApp) {
- App.openApp();
- } else {
- App.reconnectApp(lastUpdateIDAppliedToClient);
- }
- });
+ NetworkConnection.onReconnect(handleNetworkReconnect);
PusherConnectionManager.init();
Pusher.init({
appKey: CONFIG.PUSHER.APP_KEY,
@@ -178,7 +190,7 @@ function AuthScreens({lastUpdateIDAppliedToClient, session, lastOpenedPublicRoom
if (shouldGetAllData) {
App.openApp();
} else {
- App.reconnectApp(lastUpdateIDAppliedToClient);
+ App.reconnectApp(initialLastUpdateIDAppliedToClient);
}
PriorityMode.autoSwitchToFocusMode();
@@ -327,7 +339,7 @@ export default withOnyx({
isUsingMemoryOnlyKeys: {
key: ONYXKEYS.IS_USING_MEMORY_ONLY_KEYS,
},
- lastUpdateIDAppliedToClient: {
+ initialLastUpdateIDAppliedToClient: {
key: ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT,
},
})(AuthScreensMemoized);
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx
index e177f1c2003d..9d4be56ba08f 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx
@@ -62,6 +62,7 @@ function createModalStackNavigator(screens:
key={name}
name={name}
getComponent={(screens as Required)[name as Screen]}
+ initialParams={{layout: 'narrow'} as TStackParams[string]}
/>
))}
@@ -103,8 +104,7 @@ const MoneyRequestModalStackNavigator = createModalStackNavigator require('../../../pages/AddPersonalBankAccountPage').default as React.ComponentType,
[SCREENS.IOU_SEND.ADD_DEBIT_CARD]: () => require('../../../pages/settings/Wallet/AddDebitCardPage').default as React.ComponentType,
[SCREENS.IOU_SEND.ENABLE_PAYMENTS]: () => require('../../../pages/EnablePayments/EnablePaymentsPage').default as React.ComponentType,
- [SCREENS.MONEY_REQUEST.WAYPOINT]: () => require('../../../pages/iou/NewDistanceRequestWaypointEditorPage').default as React.ComponentType,
- [SCREENS.MONEY_REQUEST.EDIT_WAYPOINT]: () => require('../../../pages/iou/MoneyRequestEditWaypointPage').default as React.ComponentType,
+ [SCREENS.MONEY_REQUEST.WAYPOINT]: () => require('../../../pages/iou/MoneyRequestWaypointPage').default as React.ComponentType,
[SCREENS.MONEY_REQUEST.DISTANCE]: () => require('../../../pages/iou/NewDistanceRequestPage').default as React.ComponentType,
[SCREENS.MONEY_REQUEST.RECEIPT]: () => require('../../../pages/EditRequestReceiptPage').default as React.ComponentType,
});
@@ -283,6 +283,10 @@ const ReferralModalStackNavigator = createModalStackNavigator require('../../../pages/ReferralDetailsPage').default as React.ComponentType,
});
+const ProcessMoneyRequestHoldStackNavigator = createModalStackNavigator({
+ [SCREENS.PROCESS_MONEY_REQUEST_HOLD_ROOT]: () => require('../../../pages/ProcessMoneyRequestHoldPage').default as React.ComponentType,
+});
+
export {
MoneyRequestModalStackNavigator,
SplitDetailsModalStackNavigator,
@@ -309,4 +313,5 @@ export {
RoomMembersModalStackNavigator,
RoomInviteModalStackNavigator,
ReferralModalStackNavigator,
+ ProcessMoneyRequestHoldStackNavigator,
};
diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx
index ca33b32113bb..7721a64adea9 100644
--- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx
+++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx
@@ -1,6 +1,6 @@
import type {StackScreenProps} from '@react-navigation/stack';
import {createStackNavigator} from '@react-navigation/stack';
-import React, {useMemo} from 'react';
+import React, {useMemo, useRef} from 'react';
import {View} from 'react-native';
import NoDropZone from '@components/DragAndDrop/NoDropZone';
import useThemeStyles from '@hooks/useThemeStyles';
@@ -20,10 +20,21 @@ function RightModalNavigator({navigation}: RightModalNavigatorProps) {
const styles = useThemeStyles();
const {isSmallScreenWidth} = useWindowDimensions();
const screenOptions = useMemo(() => ModalNavigatorScreenOptions(styles), [styles]);
+ const isExecutingRef = useRef(false);
return (
- {!isSmallScreenWidth && }
+ {!isSmallScreenWidth && (
+ {
+ if (isExecutingRef.current) {
+ return;
+ }
+ isExecutingRef.current = true;
+ navigation.goBack();
+ }}
+ />
+ )}
+
diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts
index 10cee2c85952..020719e2dc36 100644
--- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts
+++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts
@@ -1,7 +1,6 @@
import type {NavigationState, PartialState, RouterConfigOptions, StackNavigationState} from '@react-navigation/native';
import {StackRouter} from '@react-navigation/native';
import type {ParamListBase} from '@react-navigation/routers';
-import getIsSmallScreenWidth from '@libs/getIsSmallScreenWidth';
import NAVIGATORS from '@src/NAVIGATORS';
import SCREENS from '@src/SCREENS';
import type {ResponsiveStackNavigatorRouterOptions} from './types';
@@ -65,9 +64,8 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) {
return {
...stackRouter,
getRehydratedState(partialState: StackNavigationState, {routeNames, routeParamList, routeGetIdList}: RouterConfigOptions): StackNavigationState {
- const isSmallScreenWidth = getIsSmallScreenWidth();
// Make sure that there is at least one CentralPaneNavigator (ReportScreen by default) in the state if this is a wide layout
- if (!isAtLeastOneCentralPaneNavigatorInState(partialState) && !isSmallScreenWidth) {
+ if (!isAtLeastOneCentralPaneNavigatorInState(partialState) && !options.getIsSmallScreenWidth()) {
// If we added a route we need to make sure that the state.stale is true to generate new key for this route
// eslint-disable-next-line no-param-reassign
diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.native.tsx b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.native.tsx
index 151dd0a0f893..5f1010da2ed1 100644
--- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.native.tsx
+++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.native.tsx
@@ -24,6 +24,8 @@ function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) {
children: props.children,
screenOptions: props.screenOptions,
initialRouteName: props.initialRouteName,
+ // Options for useNavigationBuilder won't update on prop change, so we need to pass a getter for the router to have the current state of isSmallScreenWidth.
+ getIsSmallScreenWidth: () => isSmallScreenWidthRef.current,
});
return (
diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx
index 3f6025d5ff0c..06845e6e6f61 100644
--- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx
+++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx
@@ -46,6 +46,8 @@ function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) {
children: props.children,
screenOptions: props.screenOptions,
initialRouteName: props.initialRouteName,
+ // Options for useNavigationBuilder won't update on prop change, so we need to pass a getter for the router to have the current state of isSmallScreenWidth.
+ getIsSmallScreenWidth: () => isSmallScreenWidthRef.current,
});
const stateToRender = useMemo(() => {
diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/types.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/types.ts
index 09d35e2a1680..ea94fed19b11 100644
--- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/types.ts
+++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/types.ts
@@ -5,7 +5,9 @@ type ResponsiveStackNavigatorConfig = {
isSmallScreenWidth: boolean;
};
-type ResponsiveStackNavigatorRouterOptions = StackRouterOptions;
+type ResponsiveStackNavigatorRouterOptions = StackRouterOptions & {
+ getIsSmallScreenWidth: () => boolean;
+};
type ResponsiveStackNavigatorProps = DefaultNavigatorOptions, StackNavigationOptions, StackNavigationEventMap> &
ResponsiveStackNavigatorConfig;
diff --git a/src/libs/Navigation/AppNavigator/createModalCardStyleInterpolator.ts b/src/libs/Navigation/AppNavigator/createModalCardStyleInterpolator.ts
new file mode 100644
index 000000000000..7a88976b3e03
--- /dev/null
+++ b/src/libs/Navigation/AppNavigator/createModalCardStyleInterpolator.ts
@@ -0,0 +1,40 @@
+import type {StackCardInterpolatedStyle, StackCardInterpolationProps} from '@react-navigation/stack';
+import {Animated} from 'react-native';
+import type {StyleUtilsType} from '@styles/utils';
+import variables from '@styles/variables';
+
+type ModalCardStyleInterpolator = (
+ isSmallScreenWidth: boolean,
+ isFullScreenModal: boolean,
+ stackCardInterpolationProps: StackCardInterpolationProps,
+ outputRangeMultiplier?: number,
+) => StackCardInterpolatedStyle;
+type CreateModalCardStyleInterpolator = (StyleUtils: StyleUtilsType) => ModalCardStyleInterpolator;
+
+const createModalCardStyleInterpolator: CreateModalCardStyleInterpolator =
+ (StyleUtils) =>
+ (isSmallScreenWidth, isFullScreenModal, {current: {progress}, inverted, layouts: {screen}}, outputRangeMultiplier = 1) => {
+ const translateX = Animated.multiply(
+ progress.interpolate({
+ inputRange: [0, 1],
+ outputRange: [outputRangeMultiplier * (isSmallScreenWidth ? screen.width : variables.sideBarWidth), 0],
+ extrapolate: 'clamp',
+ }),
+ inverted,
+ );
+
+ const cardStyle = StyleUtils.getCardStyles(screen.width);
+
+ if (!isFullScreenModal || isSmallScreenWidth) {
+ cardStyle.transform = [{translateX}];
+ }
+
+ return {
+ containerStyle: {
+ overflow: 'hidden',
+ },
+ cardStyle,
+ };
+ };
+
+export default createModalCardStyleInterpolator;
diff --git a/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts b/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts
index 1c0f06283226..31b8d49e74c0 100644
--- a/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts
+++ b/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts
@@ -1,9 +1,9 @@
import type {StackCardInterpolationProps, StackNavigationOptions} from '@react-navigation/stack';
import type {ThemeStyles} from '@styles/index';
-import getNavigationModalCardStyle from '@styles/utils/getNavigationModalCardStyles';
+import type {StyleUtilsType} from '@styles/utils';
import variables from '@styles/variables';
import CONFIG from '@src/CONFIG';
-import modalCardStyleInterpolator from './modalCardStyleInterpolator';
+import createModalCardStyleInterpolator from './createModalCardStyleInterpolator';
type ScreenOptions = Record;
@@ -17,75 +17,83 @@ const commonScreenOptions: StackNavigationOptions = {
const SLIDE_LEFT_OUTPUT_RANGE_MULTIPLIER = -1;
-export default (isSmallScreenWidth: boolean, themeStyles: ThemeStyles): ScreenOptions => ({
- rightModalNavigator: {
- ...commonScreenOptions,
- cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, false, props),
- presentation: 'transparentModal',
-
- // We want pop in RHP since there are some flows that would work weird otherwise
- animationTypeForReplace: 'pop',
- cardStyle: {
- ...getNavigationModalCardStyle(),
-
- // This is necessary to cover translated sidebar with overlay.
- width: isSmallScreenWidth ? '100%' : '200%',
- // Excess space should be on the left so we need to position from right.
- right: 0,
+type GetRootNavigatorScreenOptions = (isSmallScreenWidth: boolean, styles: ThemeStyles, StyleUtils: StyleUtilsType) => ScreenOptions;
+
+const getRootNavigatorScreenOptions: GetRootNavigatorScreenOptions = (isSmallScreenWidth, themeStyles, StyleUtils) => {
+ const modalCardStyleInterpolator = createModalCardStyleInterpolator(StyleUtils);
+
+ return {
+ rightModalNavigator: {
+ ...commonScreenOptions,
+ cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, false, props),
+ presentation: 'transparentModal',
+
+ // We want pop in RHP since there are some flows that would work weird otherwise
+ animationTypeForReplace: 'pop',
+ cardStyle: {
+ ...StyleUtils.getNavigationModalCardStyle(),
+
+ // This is necessary to cover translated sidebar with overlay.
+ width: isSmallScreenWidth ? '100%' : '200%',
+ // Excess space should be on the left so we need to position from right.
+ right: 0,
+ },
},
- },
- leftModalNavigator: {
- ...commonScreenOptions,
- cardStyleInterpolator: (props) => modalCardStyleInterpolator(isSmallScreenWidth, false, props, SLIDE_LEFT_OUTPUT_RANGE_MULTIPLIER),
- presentation: 'transparentModal',
-
- // We want pop in LHP since there are some flows that would work weird otherwise
- animationTypeForReplace: 'pop',
- cardStyle: {
- ...getNavigationModalCardStyle(),
-
- // This is necessary to cover translated sidebar with overlay.
- width: isSmallScreenWidth ? '100%' : '200%',
-
- // LHP should be displayed in place of the sidebar
- left: isSmallScreenWidth ? 0 : -variables.sideBarWidth,
+ leftModalNavigator: {
+ ...commonScreenOptions,
+ cardStyleInterpolator: (props) => modalCardStyleInterpolator(isSmallScreenWidth, false, props, SLIDE_LEFT_OUTPUT_RANGE_MULTIPLIER),
+ presentation: 'transparentModal',
+
+ // We want pop in LHP since there are some flows that would work weird otherwise
+ animationTypeForReplace: 'pop',
+ cardStyle: {
+ ...StyleUtils.getNavigationModalCardStyle(),
+
+ // This is necessary to cover translated sidebar with overlay.
+ width: isSmallScreenWidth ? '100%' : '200%',
+
+ // LHP should be displayed in place of the sidebar
+ left: isSmallScreenWidth ? 0 : -variables.sideBarWidth,
+ },
},
- },
- homeScreen: {
- title: CONFIG.SITE_TITLE,
- ...commonScreenOptions,
- cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, false, props),
-
- cardStyle: {
- ...getNavigationModalCardStyle(),
- width: isSmallScreenWidth ? '100%' : variables.sideBarWidth,
-
- // We need to shift the sidebar to not be covered by the StackNavigator so it can be clickable.
- marginLeft: isSmallScreenWidth ? 0 : -variables.sideBarWidth,
- ...(isSmallScreenWidth ? {} : themeStyles.borderRight),
+ homeScreen: {
+ title: CONFIG.SITE_TITLE,
+ ...commonScreenOptions,
+ cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, false, props),
+
+ cardStyle: {
+ ...StyleUtils.getNavigationModalCardStyle(),
+ width: isSmallScreenWidth ? '100%' : variables.sideBarWidth,
+
+ // We need to shift the sidebar to not be covered by the StackNavigator so it can be clickable.
+ marginLeft: isSmallScreenWidth ? 0 : -variables.sideBarWidth,
+ ...(isSmallScreenWidth ? {} : themeStyles.borderRight),
+ },
},
- },
- fullScreen: {
- ...commonScreenOptions,
- cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, true, props),
- cardStyle: {
- ...getNavigationModalCardStyle(),
+ fullScreen: {
+ ...commonScreenOptions,
+ cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, true, props),
+ cardStyle: {
+ ...StyleUtils.getNavigationModalCardStyle(),
- // This is necessary to cover whole screen. Including translated sidebar.
- marginLeft: isSmallScreenWidth ? 0 : -variables.sideBarWidth,
+ // This is necessary to cover whole screen. Including translated sidebar.
+ marginLeft: isSmallScreenWidth ? 0 : -variables.sideBarWidth,
+ },
},
- },
- centralPaneNavigator: {
- title: CONFIG.SITE_TITLE,
- ...commonScreenOptions,
- animationEnabled: isSmallScreenWidth,
- cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, true, props),
+ centralPaneNavigator: {
+ title: CONFIG.SITE_TITLE,
+ ...commonScreenOptions,
+ animationEnabled: isSmallScreenWidth,
+ cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, true, props),
- cardStyle: {
- ...getNavigationModalCardStyle(),
- paddingRight: isSmallScreenWidth ? 0 : variables.sideBarWidth,
+ cardStyle: {
+ ...StyleUtils.getNavigationModalCardStyle(),
+ paddingRight: isSmallScreenWidth ? 0 : variables.sideBarWidth,
+ },
},
- },
-});
+ };
+};
+
+export default getRootNavigatorScreenOptions;
diff --git a/src/libs/Navigation/AppNavigator/modalCardStyleInterpolator.ts b/src/libs/Navigation/AppNavigator/modalCardStyleInterpolator.ts
deleted file mode 100644
index fd59b02e724d..000000000000
--- a/src/libs/Navigation/AppNavigator/modalCardStyleInterpolator.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import type {StackCardInterpolatedStyle, StackCardInterpolationProps} from '@react-navigation/stack';
-import {Animated} from 'react-native';
-import getCardStyles from '@styles/utils/cardStyles';
-import variables from '@styles/variables';
-
-export default (
- isSmallScreenWidth: boolean,
- isFullScreenModal: boolean,
- {current: {progress}, inverted, layouts: {screen}}: StackCardInterpolationProps,
- outputRangeMultiplier = 1,
-): StackCardInterpolatedStyle => {
- const translateX = Animated.multiply(
- progress.interpolate({
- inputRange: [0, 1],
- outputRange: [outputRangeMultiplier * (isSmallScreenWidth ? screen.width : variables.sideBarWidth), 0],
- extrapolate: 'clamp',
- }),
- inverted,
- );
-
- const cardStyle = getCardStyles(screen.width);
-
- if (!isFullScreenModal || isSmallScreenWidth) {
- cardStyle.transform = [{translateX}];
- }
-
- return {
- containerStyle: {
- overflow: 'hidden',
- },
- cardStyle,
- };
-};
diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts
index cc77cd1c4908..91285821fe9f 100644
--- a/src/libs/Navigation/Navigation.ts
+++ b/src/libs/Navigation/Navigation.ts
@@ -73,7 +73,7 @@ function getActiveRouteIndex(stateOrRoute: StateOrRoute, index?: number): number
* @param path - Path that you are looking for.
* @return - Returns distance to path or -1 if the path is not found in root navigator.
*/
-function getDistanceFromPathInRootNavigator(path: string): number {
+function getDistanceFromPathInRootNavigator(path?: string): number {
let currentState = navigationRef.getRootState();
for (let index = 0; index < 5; index++) {
@@ -125,7 +125,8 @@ function isActiveRoute(routePath: Route): boolean {
let activeRoute = getActiveRoute();
activeRoute = activeRoute.startsWith('/') ? activeRoute.substring(1) : activeRoute;
- return activeRoute === routePath;
+ // We remove redundant (consecutive and trailing) slashes from path before matching
+ return activeRoute === routePath.replace(CONST.REGEX.ROUTES.REDUNDANT_SLASHES, (match, p1) => (p1 ? '/' : ''));
}
/**
@@ -148,7 +149,7 @@ function navigate(route: Route = ROUTES.HOME, type?: string) {
* @param shouldEnforceFallback - Enforces navigation to fallback route
* @param shouldPopToTop - Should we navigate to LHN on back press
*/
-function goBack(fallbackRoute: Route, shouldEnforceFallback = false, shouldPopToTop = false) {
+function goBack(fallbackRoute?: Route, shouldEnforceFallback = false, shouldPopToTop = false) {
if (!canNavigate('goBack')) {
return;
}
diff --git a/src/libs/Navigation/OnyxTabNavigator.tsx b/src/libs/Navigation/OnyxTabNavigator.tsx
index 624aaec72bda..b5466a9bbc2f 100644
--- a/src/libs/Navigation/OnyxTabNavigator.tsx
+++ b/src/libs/Navigation/OnyxTabNavigator.tsx
@@ -7,6 +7,7 @@ import type {OnyxEntry} from 'react-native-onyx/lib/types';
import Tab from '@userActions/Tab';
import ONYXKEYS from '@src/ONYXKEYS';
import type ChildrenProps from '@src/types/utils/ChildrenProps';
+import {defaultScreenOptions} from './OnyxTabNavigatorConfig';
type OnyxTabNavigatorOnyxProps = {
selectedTab: OnyxEntry;
@@ -51,6 +52,7 @@ function OnyxTabNavigator({id, selectedTab = '', children, onTabSelected = () =>
},
...(screenListeners ?? {}),
}}
+ screenOptions={defaultScreenOptions}
>
{children}
diff --git a/src/libs/Navigation/OnyxTabNavigatorConfig/index.ts b/src/libs/Navigation/OnyxTabNavigatorConfig/index.ts
new file mode 100644
index 000000000000..8f61e38ca531
--- /dev/null
+++ b/src/libs/Navigation/OnyxTabNavigatorConfig/index.ts
@@ -0,0 +1,8 @@
+const defaultScreenOptions = {
+ animationEnabled: true,
+} as const;
+
+export {
+ // eslint-disable-next-line import/prefer-default-export
+ defaultScreenOptions,
+};
diff --git a/src/libs/Navigation/OnyxTabNavigatorConfig/index.website.ts b/src/libs/Navigation/OnyxTabNavigatorConfig/index.website.ts
new file mode 100644
index 000000000000..724e8be05123
--- /dev/null
+++ b/src/libs/Navigation/OnyxTabNavigatorConfig/index.website.ts
@@ -0,0 +1,8 @@
+const defaultScreenOptions = {
+ animationEnabled: false,
+} as const;
+
+export {
+ // eslint-disable-next-line import/prefer-default-export
+ defaultScreenOptions,
+};
diff --git a/src/libs/Navigation/linkingConfig.ts b/src/libs/Navigation/linkingConfig.ts
index 3b2350afcc43..1a495e92eb80 100644
--- a/src/libs/Navigation/linkingConfig.ts
+++ b/src/libs/Navigation/linkingConfig.ts
@@ -433,8 +433,6 @@ const linkingConfig: LinkingOptions = {
[SCREENS.MONEY_REQUEST.CATEGORY]: ROUTES.MONEY_REQUEST_CATEGORY.route,
[SCREENS.MONEY_REQUEST.TAG]: ROUTES.MONEY_REQUEST_TAG.route,
[SCREENS.MONEY_REQUEST.MERCHANT]: ROUTES.MONEY_REQUEST_MERCHANT.route,
- [SCREENS.MONEY_REQUEST.WAYPOINT]: ROUTES.MONEY_REQUEST_WAYPOINT.route,
- [SCREENS.MONEY_REQUEST.EDIT_WAYPOINT]: ROUTES.MONEY_REQUEST_EDIT_WAYPOINT.route,
[SCREENS.MONEY_REQUEST.RECEIPT]: ROUTES.MONEY_REQUEST_RECEIPT.route,
[SCREENS.MONEY_REQUEST.DISTANCE]: ROUTES.MONEY_REQUEST_DISTANCE.route,
[SCREENS.IOU_SEND.ENABLE_PAYMENTS]: ROUTES.IOU_SEND_ENABLE_PAYMENTS,
@@ -492,6 +490,11 @@ const linkingConfig: LinkingOptions = {
[SCREENS.REFERRAL_DETAILS]: ROUTES.REFERRAL_DETAILS_MODAL.route,
},
},
+ ProcessMoneyRequestHold: {
+ screens: {
+ ProcessMoneyRequestHold_Root: ROUTES.PROCESS_MONEY_REQUEST_HOLD,
+ },
+ },
},
},
},
diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts
index 505bc82180f4..8563db7db172 100644
--- a/src/libs/Navigation/types.ts
+++ b/src/libs/Navigation/types.ts
@@ -241,12 +241,6 @@ type MoneyRequestNavigatorParamList = {
waypointIndex: string;
threadReportID: number;
};
- [SCREENS.MONEY_REQUEST.EDIT_WAYPOINT]: {
- iouType: string;
- transactionID: string;
- waypointIndex: string;
- threadReportID: number;
- };
[SCREENS.MONEY_REQUEST.DISTANCE]: {
iouType: ValueOf;
reportID: string;
@@ -331,6 +325,10 @@ type ReferralDetailsNavigatorParamList = {
[SCREENS.REFERRAL_DETAILS]: undefined;
};
+type ProcessMoneyRequestHoldNavigatorParamList = {
+ [SCREENS.PROCESS_MONEY_REQUEST_HOLD_ROOT]: undefined;
+};
+
type PrivateNotesNavigatorParamList = {
[SCREENS.PRIVATE_NOTES.VIEW]: {
reportID: string;
@@ -372,6 +370,7 @@ type RightModalNavigatorParamList = {
[SCREENS.RIGHT_MODAL.FLAG_COMMENT]: NavigatorScreenParams;
[SCREENS.RIGHT_MODAL.EDIT_REQUEST]: NavigatorScreenParams;
[SCREENS.RIGHT_MODAL.SIGN_IN]: NavigatorScreenParams;
+ [SCREENS.RIGHT_MODAL.PROCESS_MONEY_REQUEST_HOLD]: NavigatorScreenParams;
[SCREENS.RIGHT_MODAL.REFERRAL]: NavigatorScreenParams;
[SCREENS.RIGHT_MODAL.PRIVATE_NOTES]: NavigatorScreenParams;
};
diff --git a/src/libs/Network/SequentialQueue.ts b/src/libs/Network/SequentialQueue.ts
index f9a7cd0a996b..b22a9612a23f 100644
--- a/src/libs/Network/SequentialQueue.ts
+++ b/src/libs/Network/SequentialQueue.ts
@@ -176,7 +176,7 @@ function push(request: OnyxRequest) {
flush();
}
-function getCurrentRequest(): OnyxRequest | Promise {
+function getCurrentRequest(): Promise {
if (currentRequest === null) {
return Promise.resolve();
}
diff --git a/src/libs/Network/enhanceParameters.ts b/src/libs/Network/enhanceParameters.ts
index 3fadeea7447c..e14acda5ff56 100644
--- a/src/libs/Network/enhanceParameters.ts
+++ b/src/libs/Network/enhanceParameters.ts
@@ -1,3 +1,4 @@
+import * as Environment from '@libs/Environment/Environment';
import getPlatform from '@libs/getPlatform';
import CONFIG from '@src/CONFIG';
import * as NetworkStore from './NetworkStore';
@@ -37,6 +38,8 @@ export default function enhanceParameters(command: string, parameters: Record {
@@ -83,6 +84,18 @@ Onyx.connect({
const sortedReportActions = ReportActionUtils.getSortedReportActions(_.toArray(actions), true);
allSortedReportActions[reportID] = sortedReportActions;
lastReportActions[reportID] = _.first(sortedReportActions);
+
+ // The report is only visible if it is the last action not deleted that
+ // does not match a closed or created state.
+ const reportActionsForDisplay = _.filter(
+ sortedReportActions,
+ (reportAction, actionKey) =>
+ ReportActionUtils.shouldReportActionBeVisible(reportAction, actionKey) &&
+ !ReportActionUtils.isWhisperAction(reportAction) &&
+ reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.CREATED &&
+ reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
+ );
+ visibleReportActionItems[reportID] = reportActionsForDisplay[reportActionsForDisplay.length - 1];
},
});
@@ -116,7 +129,7 @@ Onyx.connect({
* @return {String}
*/
function addSMSDomainIfPhoneNumber(login) {
- const parsedPhoneNumber = parsePhoneNumber(login);
+ const parsedPhoneNumber = PhoneNumber.parsePhoneNumber(login);
if (parsedPhoneNumber.possible && !Str.isValidEmail(login)) {
return parsedPhoneNumber.number.e164 + CONST.SMS.DOMAIN;
}
@@ -221,6 +234,7 @@ function getParticipantsOption(participant, personalDetails) {
],
phoneNumber: lodashGet(detail, 'phoneNumber', ''),
selected: participant.selected,
+ isSelected: participant.selected,
searchText: participant.searchText,
};
}
@@ -322,9 +336,9 @@ function getSearchText(report, reportName, personalDetailList, isChatRoomOrPolic
Array.prototype.push.apply(searchTerms, chatRoomSubtitle.split(/[,\s]/));
} else {
- const participantAccountIDs = report.participantAccountIDs || [];
- for (let i = 0; i < participantAccountIDs.length; i++) {
- const accountID = participantAccountIDs[i];
+ const visibleChatMemberAccountIDs = report.visibleChatMemberAccountIDs || [];
+ for (let i = 0; i < visibleChatMemberAccountIDs.length; i++) {
+ const accountID = visibleChatMemberAccountIDs[i];
if (allPersonalDetails[accountID] && allPersonalDetails[accountID].login) {
searchTerms = searchTerms.concat(allPersonalDetails[accountID].login);
@@ -406,7 +420,7 @@ function getLastMessageTextForReport(report) {
} else if (ReportActionUtils.isReimbursementQueuedAction(lastReportAction)) {
lastMessageTextFromReport = ReportUtils.getReimbursementQueuedActionMessage(lastReportAction, report);
} else if (ReportActionUtils.isReimbursementDeQueuedAction(lastReportAction)) {
- lastMessageTextFromReport = ReportUtils.getReimbursementDeQueuedActionMessage(report);
+ lastMessageTextFromReport = ReportUtils.getReimbursementDeQueuedActionMessage(lastReportAction, report);
} else if (ReportActionUtils.isDeletedParentAction(lastReportAction) && ReportUtils.isChatReport(report)) {
lastMessageTextFromReport = ReportUtils.getDeletedParentActionMessageForChatReport(lastReportAction);
} else if (ReportUtils.isReportMessageAttachment({text: report.lastMessageText, html: report.lastMessageHtml, translationKey: report.lastMessageTranslationKey})) {
@@ -506,7 +520,7 @@ function createOption(accountIDs, personalDetails, report, reportActions = {}, {
result.isPinned = report.isPinned;
result.iouReportID = report.iouReportID;
result.keyForList = String(report.reportID);
- result.tooltipText = ReportUtils.getReportParticipantsTitle(report.participantAccountIDs || []);
+ result.tooltipText = ReportUtils.getReportParticipantsTitle(report.visibleChatMemberAccountIDs || []);
result.isWaitingOnBankAccount = report.isWaitingOnBankAccount;
result.policyID = report.policyID;
@@ -519,7 +533,7 @@ function createOption(accountIDs, personalDetails, report, reportActions = {}, {
hasMultipleParticipants && lastActorDetails && lastActorDetails.accountID !== currentUserAccountID
? lastActorDetails.firstName || PersonalDetailsUtils.getDisplayNameOrDefault(lastActorDetails)
: '';
- let lastMessageText = lastActorDisplayName ? `${lastActorDisplayName}: ${lastMessageTextFromReport}` : lastMessageTextFromReport;
+ let lastMessageText = lastMessageTextFromReport;
if (result.isArchivedRoom) {
const archiveReason =
@@ -531,12 +545,19 @@ function createOption(accountIDs, personalDetails, report, reportActions = {}, {
});
}
+ const lastAction = visibleReportActionItems[report.reportID];
+ const shouldDisplayLastActorName = lastAction && lastAction.actionName !== CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW && lastAction.actionName !== CONST.REPORT.ACTIONS.TYPE.IOU;
+
+ if (shouldDisplayLastActorName && lastActorDisplayName && lastMessageTextFromReport) {
+ lastMessageText = `${lastActorDisplayName}: ${lastMessageTextFromReport}`;
+ }
+
if (result.isThread || result.isMoneyRequestReport) {
result.alternateText = lastMessageTextFromReport.length > 0 ? lastMessageText : Localize.translate(preferredLocale, 'report.noActivityYet');
} else if (result.isChatRoom || result.isPolicyExpenseChat) {
result.alternateText = showChatPreviewLine && !forcePolicyNamePreview && lastMessageText ? lastMessageText : subtitle;
} else if (result.isTaskReport) {
- result.alternateText = showChatPreviewLine && lastMessageText ? lastMessageTextFromReport : Localize.translate(preferredLocale, 'report.noActivityYet');
+ result.alternateText = showChatPreviewLine && lastMessageText ? lastMessageText : Localize.translate(preferredLocale, 'report.noActivityYet');
} else {
result.alternateText = showChatPreviewLine && lastMessageText ? lastMessageText : LocalePhoneNumber.formatPhoneNumber(personalDetail.login);
}
@@ -573,7 +594,7 @@ function getPolicyExpenseReportOption(report) {
const expenseReport = policyExpenseReports[`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`];
const option = createOption(
- expenseReport.participantAccountIDs,
+ expenseReport.visibleChatMemberAccountIDs,
allPersonalDetails,
expenseReport,
{},
@@ -587,6 +608,7 @@ function getPolicyExpenseReportOption(report) {
option.text = ReportUtils.getPolicyName(expenseReport);
option.alternateText = Localize.translateLocal('workspace.common.workspace');
option.selected = report.selected;
+ option.isSelected = report.selected;
return option;
}
@@ -1211,6 +1233,25 @@ function getTaxRatesSection(policyTaxRates, selectedOptions, searchInputValue) {
return policyRatesSections;
}
+/**
+ * Checks if a report option is selected based on matching accountID or reportID.
+ *
+ * @param {Object} reportOption - The report option to be checked.
+ * @param {Object[]} selectedOptions - Array of selected options to compare with.
+ * @param {number} reportOption.accountID - The account ID of the report option.
+ * @param {number} reportOption.reportID - The report ID of the report option.
+ * @param {number} [selectedOptions[].accountID] - The account ID in the selected options.
+ * @param {number} [selectedOptions[].reportID] - The report ID in the selected options.
+ * @returns {boolean} True if the report option matches any of the selected options by accountID or reportID, false otherwise.
+ */
+function isReportSelected(reportOption, selectedOptions) {
+ if (!selectedOptions || selectedOptions.length === 0) {
+ return false;
+ }
+
+ return _.some(selectedOptions, (option) => (option.accountID && option.accountID === reportOption.accountID) || (option.reportID && option.reportID === reportOption.reportID));
+}
+
/**
* Build the options
*
@@ -1313,7 +1354,7 @@ function getOptions(
let recentReportOptions = [];
let personalDetailsOptions = [];
const reportMapForAccountIDs = {};
- const parsedPhoneNumber = parsePhoneNumber(LoginUtils.appendCountryCode(Str.removeSMSDomain(searchInputValue)));
+ const parsedPhoneNumber = PhoneNumber.parsePhoneNumber(LoginUtils.appendCountryCode(Str.removeSMSDomain(searchInputValue)));
const searchValue = parsedPhoneNumber.possible ? parsedPhoneNumber.number.e164 : searchInputValue.toLowerCase();
// Filter out all the reports that shouldn't be displayed
@@ -1342,7 +1383,7 @@ function getOptions(
const isTaskReport = ReportUtils.isTaskReport(report);
const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(report);
const isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report);
- const accountIDs = report.participantAccountIDs || [];
+ const accountIDs = report.visibleChatMemberAccountIDs || [];
if (isPolicyExpenseChat && report.isOwnPolicyExpenseChat && !includeOwnedWorkspaceChats) {
return;
@@ -1390,11 +1431,13 @@ function getOptions(
);
});
- // We're only picking personal details that have logins set
- // This is a temporary fix for all the logic that's been breaking because of the new privacy changes
- // See https://github.com/Expensify/Expensify/issues/293465 for more context
- // Moreover, we should not override the personalDetails object, otherwise the createOption util won't work properly, it returns incorrect tooltipText
- const havingLoginPersonalDetails = !includeP2P ? {} : _.pick(personalDetails, (detail) => Boolean(detail.login) && !detail.isOptimisticPersonalDetail);
+ /*
+ We're only picking personal details that have logins and accountIDs set (sometimes the __fake__ account with `ID = 0` is present in the personal details collection)
+ This is a temporary fix for all the logic that's been breaking because of the new privacy changes
+ See https://github.com/Expensify/Expensify/issues/293465, https://github.com/Expensify/App/issues/33415 for more context
+ Moreover, we should not override the personalDetails object, otherwise the createOption util won't work properly, it returns incorrect tooltipText
+ */
+ const havingLoginPersonalDetails = !includeP2P ? {} : _.pick(personalDetails, (detail) => !!detail.login && !!detail.accountID && !detail.isOptimisticPersonalDetail);
let allPersonalDetailsOptions = _.map(havingLoginPersonalDetails, (personalDetail) =>
createOption([personalDetail.accountID], personalDetails, reportMapForAccountIDs[personalDetail.accountID], reportActions, {
showChatPreviewLine,
@@ -1468,6 +1511,8 @@ function getOptions(
}
}
+ reportOption.isSelected = isReportSelected(reportOption, selectedOptions);
+
recentReportOptions.push(reportOption);
// Add this login to the exclude list so it won't appear when we process the personal details
@@ -1823,7 +1868,7 @@ function getHeaderMessage(hasSelectableOptions, hasUserToInvite, searchValue, ma
return Localize.translate(preferredLocale, 'common.maxParticipantsReached', {count: CONST.REPORT.MAXIMUM_PARTICIPANTS});
}
- const isValidPhone = parsePhoneNumber(LoginUtils.appendCountryCode(searchValue)).possible;
+ const isValidPhone = PhoneNumber.parsePhoneNumber(LoginUtils.appendCountryCode(searchValue)).possible;
const isValidEmail = Str.isValidEmail(searchValue);
diff --git a/src/libs/Performance.tsx b/src/libs/Performance.tsx
index a2667955326d..90a13b84d7f7 100644
--- a/src/libs/Performance.tsx
+++ b/src/libs/Performance.tsx
@@ -14,7 +14,7 @@ type WrappedComponentConfig = {id: string};
type PerformanceEntriesCallback = (entry: PerformanceEntry) => void;
-type Phase = 'mount' | 'update';
+type Phase = 'mount' | 'update' | 'nested-update';
type WithRenderTraceHOC =
>(WrappedComponent: React.ComponentType
) => React.ComponentType
>;
diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts
index 85e64651980e..ce5e0e674c59 100644
--- a/src/libs/Permissions.ts
+++ b/src/libs/Permissions.ts
@@ -22,15 +22,6 @@ function canUseReportFields(betas: OnyxEntry): boolean {
return !!betas?.includes(CONST.BETAS.REPORT_FIELDS) || canUseAllBetas(betas);
}
-/**
- * We're requiring you to be added to the policy rooms beta on dev,
- * since contributors have been reporting a number of false issues related to the feature being under development.
- * See https://expensify.slack.com/archives/C01GTK53T8Q/p1641921996319400?thread_ts=1641598356.166900&cid=C01GTK53T8Q
- */
-function canUsePolicyRooms(betas: OnyxEntry): boolean {
- return !!betas?.includes(CONST.BETAS.POLICY_ROOMS) || canUseAllBetas(betas);
-}
-
function canUseViolations(betas: OnyxEntry): boolean {
return !!betas?.includes(CONST.BETAS.VIOLATIONS) || canUseAllBetas(betas);
}
@@ -46,7 +37,6 @@ export default {
canUseChronos,
canUseDefaultRooms,
canUseCommentLinking,
- canUsePolicyRooms,
canUseLinkPreviews,
canUseViolations,
canUseReportFields,
diff --git a/src/libs/PhoneNumber.ts b/src/libs/PhoneNumber.ts
new file mode 100644
index 000000000000..f92aade2c892
--- /dev/null
+++ b/src/libs/PhoneNumber.ts
@@ -0,0 +1,43 @@
+// eslint-disable-next-line no-restricted-imports
+import {parsePhoneNumber as originalParsePhoneNumber} from 'awesome-phonenumber';
+import type {ParsedPhoneNumber, ParsedPhoneNumberInvalid, PhoneNumberParseOptions} from 'awesome-phonenumber';
+import CONST from '@src/CONST';
+
+/**
+ * Wraps awesome-phonenumber's parsePhoneNumber function to handle the case where we want to treat
+ * a US phone number that's technically valid as invalid. eg: +115005550009.
+ * See https://github.com/Expensify/App/issues/28492
+ */
+function parsePhoneNumber(phoneNumber: string, options?: PhoneNumberParseOptions): ParsedPhoneNumber {
+ const parsedPhoneNumber = originalParsePhoneNumber(phoneNumber, options);
+ if (!parsedPhoneNumber.possible) {
+ return parsedPhoneNumber;
+ }
+
+ const phoneNumberWithoutSpecialChars = phoneNumber.replace(CONST.REGEX.SPECIAL_CHARS_WITHOUT_NEWLINE, '');
+ if (!/^\+11[0-9]{10}$/.test(phoneNumberWithoutSpecialChars)) {
+ return parsedPhoneNumber;
+ }
+
+ const countryCode = phoneNumberWithoutSpecialChars.substring(0, 2);
+ const phoneNumberWithoutCountryCode = phoneNumberWithoutSpecialChars.substring(2);
+
+ return {
+ ...parsedPhoneNumber,
+ valid: false,
+ possible: false,
+ number: {
+ ...parsedPhoneNumber.number,
+
+ // mimic the behavior of awesome-phonenumber
+ e164: phoneNumberWithoutSpecialChars,
+ international: `${countryCode} ${phoneNumberWithoutCountryCode}`,
+ national: phoneNumberWithoutCountryCode,
+ rfc3966: `tel:${countryCode}-${phoneNumberWithoutCountryCode}`,
+ significant: phoneNumberWithoutCountryCode,
+ },
+ } as ParsedPhoneNumberInvalid;
+}
+
+// eslint-disable-next-line import/prefer-default-export
+export {parsePhoneNumber};
diff --git a/src/libs/PopoverWithMeasuredContentUtils.ts b/src/libs/PopoverWithMeasuredContentUtils.ts
index b932249211be..5d5af6f7c83d 100644
--- a/src/libs/PopoverWithMeasuredContentUtils.ts
+++ b/src/libs/PopoverWithMeasuredContentUtils.ts
@@ -1,5 +1,5 @@
-import roundToNearestMultipleOfFour from '@styles/utils/roundToNearestMultipleOfFour';
import variables from '@styles/variables';
+import roundToNearestMultipleOfFour from './roundToNearestMultipleOfFour';
/**
* Compute the amount that the Context menu's Anchor needs to be horizontally shifted
diff --git a/src/libs/ReceiptUtils.ts b/src/libs/ReceiptUtils.ts
index 734c40271208..bcba68a3a0bd 100644
--- a/src/libs/ReceiptUtils.ts
+++ b/src/libs/ReceiptUtils.ts
@@ -66,7 +66,7 @@ function getThumbnailAndImageURIs(transaction: Transaction, receiptPath: string
image = ReceiptSVG;
}
- const isLocalFile = path.startsWith('blob:') || path.startsWith('file:');
+ const isLocalFile = typeof path === 'number' || path.startsWith('blob:') || path.startsWith('file:') || path.startsWith('/');
return {thumbnail: image, image: path, isLocalFile};
}
diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts
index c8b7e673aed4..ee4fa201ee2f 100644
--- a/src/libs/ReportActionsUtils.ts
+++ b/src/libs/ReportActionsUtils.ts
@@ -378,10 +378,20 @@ function shouldReportActionBeVisible(reportAction: OnyxEntry, key:
// All other actions are displayed except thread parents, deleted, or non-pending actions
const isDeleted = isDeletedAction(reportAction);
- const isPending = !!reportAction.pendingAction && !(!isNetworkOffline && reportAction.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE);
+ const isPending = !!reportAction.pendingAction;
return !isDeleted || isPending || isDeletedParentAction(reportAction) || isReversedTransaction(reportAction);
}
+/**
+ * Checks if the new marker should be hidden for the report action.
+ */
+function shouldHideNewMarker(reportAction: OnyxEntry): boolean {
+ if (!reportAction) {
+ return true;
+ }
+ return !isNetworkOffline && reportAction.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE;
+}
+
/**
* Checks if a reportAction is fit for display as report last action, meaning that
* it satisfies shouldReportActionBeVisible, it's not whisper action and not deleted.
@@ -841,6 +851,7 @@ export {
isWhisperAction,
isReimbursementQueuedAction,
shouldReportActionBeVisible,
+ shouldHideNewMarker,
shouldReportActionBeVisibleAsLastAction,
hasRequestFromCurrentAccount,
getFirstVisibleReportActionID,
diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 33a18b8534df..fa68b78fa18f 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -16,7 +16,7 @@ import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {Beta, Login, PersonalDetails, PersonalDetailsList, Policy, Report, ReportAction, ReportMetadata, Session, Transaction} from '@src/types/onyx';
import type {Errors, Icon, PendingAction} from '@src/types/onyx/OnyxCommon';
-import type {IOUMessage, OriginalMessageActionName, OriginalMessageCreated} from '@src/types/onyx/OriginalMessage';
+import type {IOUMessage, OriginalMessageActionName, OriginalMessageCreated, ReimbursementDeQueuedMessage} from '@src/types/onyx/OriginalMessage';
import type {Status} from '@src/types/onyx/PersonalDetails';
import type {NotificationPreference} from '@src/types/onyx/Report';
import type {Message, ReportActionBase, ReportActions} from '@src/types/onyx/ReportAction';
@@ -180,6 +180,11 @@ type OptimisticSubmittedReportAction = Pick<
'actionName' | 'actorAccountID' | 'automatic' | 'avatar' | 'isAttachment' | 'originalMessage' | 'message' | 'person' | 'reportActionID' | 'shouldShow' | 'created' | 'pendingAction'
>;
+type OptimisticCancelPaymentReportAction = Pick<
+ ReportAction,
+ 'actionName' | 'actorAccountID' | 'message' | 'originalMessage' | 'person' | 'reportActionID' | 'shouldShow' | 'created' | 'pendingAction'
+>;
+
type OptimisticEditedTaskReportAction = Pick<
ReportAction,
'reportActionID' | 'actionName' | 'pendingAction' | 'actorAccountID' | 'automatic' | 'avatar' | 'created' | 'shouldShow' | 'message' | 'person'
@@ -211,6 +216,7 @@ type OptimisticChatReport = Pick<
| 'parentReportActionID'
| 'parentReportID'
| 'participantAccountIDs'
+ | 'visibleChatMemberAccountIDs'
| 'policyID'
| 'reportID'
| 'reportName'
@@ -265,6 +271,7 @@ type OptimisticTaskReport = Pick<
| 'description'
| 'ownerAccountID'
| 'participantAccountIDs'
+ | 'visibleChatMemberAccountIDs'
| 'managerID'
| 'type'
| 'parentReportID'
@@ -302,6 +309,7 @@ type OptimisticIOUReport = Pick<
| 'managerID'
| 'ownerAccountID'
| 'participantAccountIDs'
+ | 'visibleChatMemberAccountIDs'
| 'reportID'
| 'state'
| 'stateNum'
@@ -543,7 +551,8 @@ function isExpenseReport(report: OnyxEntry | EmptyObject): boolean {
/**
* Checks if a report is an IOU report.
*/
-function isIOUReport(report: OnyxEntry): boolean {
+function isIOUReport(reportOrID: OnyxEntry | string | EmptyObject): boolean {
+ const report = typeof reportOrID === 'string' ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID;
return report?.type === CONST.REPORT.TYPE.IOU;
}
@@ -599,14 +608,15 @@ function isReportManager(report: OnyxEntry): boolean {
/**
* Checks if the supplied report has been approved
*/
-function isReportApproved(report: OnyxEntry | EmptyObject): boolean {
+function isReportApproved(reportOrID: OnyxEntry | string | EmptyObject): boolean {
+ const report = typeof reportOrID === 'string' ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID;
return report?.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED && report?.statusNum === CONST.REPORT.STATUS.APPROVED;
}
/**
* Checks if the supplied report is an expense report in Open state and status.
*/
-function isDraftExpenseReport(report: OnyxEntry): boolean {
+function isDraftExpenseReport(report: OnyxEntry | EmptyObject): boolean {
return isExpenseReport(report) && report?.stateNum === CONST.REPORT.STATE_NUM.OPEN && report?.statusNum === CONST.REPORT.STATUS.OPEN;
}
@@ -713,9 +723,17 @@ function isControlPolicyExpenseChat(report: OnyxEntry): boolean {
}
/**
- * Whether the provided report belongs to a Control or Collect policy
+ * Whether the provided report belongs to a Free, Collect or Control policy
*/
function isGroupPolicy(report: OnyxEntry): boolean {
+ const policyType = getPolicyType(report, allPolicies);
+ return policyType === CONST.POLICY.TYPE.CORPORATE || policyType === CONST.POLICY.TYPE.TEAM || policyType === CONST.POLICY.TYPE.FREE;
+}
+
+/**
+ * Whether the provided report belongs to a Control or Collect policy
+ */
+function isPaidGroupPolicy(report: OnyxEntry): boolean {
const policyType = getPolicyType(report, allPolicies);
return policyType === CONST.POLICY.TYPE.CORPORATE || policyType === CONST.POLICY.TYPE.TEAM;
}
@@ -723,8 +741,8 @@ function isGroupPolicy(report: OnyxEntry): boolean {
/**
* Whether the provided report belongs to a Control or Collect policy and is an expense chat
*/
-function isGroupPolicyExpenseChat(report: OnyxEntry): boolean {
- return isPolicyExpenseChat(report) && isGroupPolicy(report);
+function isPaidGroupPolicyExpenseChat(report: OnyxEntry): boolean {
+ return isPolicyExpenseChat(report) && isPaidGroupPolicy(report);
}
/**
@@ -737,8 +755,8 @@ function isControlPolicyExpenseReport(report: OnyxEntry): boolean {
/**
* Whether the provided report belongs to a Control or Collect policy and is an expense report
*/
-function isGroupPolicyExpenseReport(report: OnyxEntry): boolean {
- return isExpenseReport(report) && isGroupPolicy(report);
+function isPaidGroupPolicyExpenseReport(report: OnyxEntry): boolean {
+ return isExpenseReport(report) && isPaidGroupPolicy(report);
}
/**
@@ -816,7 +834,7 @@ function isConciergeChatReport(report: OnyxEntry): boolean {
/**
* Returns true if report is still being processed
*/
-function isProcessingReport(report: OnyxEntry): boolean {
+function isProcessingReport(report: OnyxEntry | EmptyObject): boolean {
return report?.stateNum === CONST.REPORT.STATE_NUM.PROCESSING && report?.statusNum === CONST.REPORT.STATUS.SUBMITTED;
}
@@ -983,6 +1001,12 @@ function hasSingleParticipant(report: OnyxEntry): boolean {
*/
function hasOnlyDistanceRequestTransactions(iouReportID: string | undefined): boolean {
const transactions = TransactionUtils.getAllReportTransactions(iouReportID);
+
+ // Early return false in case not having any transaction
+ if (!transactions || transactions.length === 0) {
+ return false;
+ }
+
return transactions.every((transaction) => TransactionUtils.isDistanceRequest(transaction));
}
@@ -1475,7 +1499,6 @@ function getDisplayNameForParticipant(accountID?: number, shouldUseShortForm = f
}
const personalDetails = getPersonalDetailsForAccountID(accountID);
- // console.log(personalDetails);
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
const formattedLogin = LocalePhoneNumber.formatPhoneNumber(personalDetails.login || '');
// This is to check if account is an invite/optimistically created one
@@ -1537,17 +1560,6 @@ function getDisplayNamesWithTooltips(
});
}
-/**
- * Gets a joined string of display names from the list of display name with tooltip objects.
- *
- */
-function getDisplayNamesStringFromTooltips(displayNamesWithTooltips: DisplayNameWithTooltips | undefined) {
- return displayNamesWithTooltips
- ?.map(({displayName}) => displayName)
- .filter(Boolean)
- .join(', ');
-}
-
/**
* For a deleted parent report action within a chat report,
* let us return the appropriate display message
@@ -1585,9 +1597,13 @@ function getReimbursementQueuedActionMessage(reportAction: OnyxEntry): string {
+function getReimbursementDeQueuedActionMessage(reportAction: OnyxEntry, report: OnyxEntry): string {
+ const amount = CurrencyUtils.convertToDisplayString(Math.abs(report?.total ?? 0), report?.currency);
+ const originalMessage = reportAction?.originalMessage as ReimbursementDeQueuedMessage | undefined;
+ if (originalMessage?.cancellationReason === CONST.REPORT.CANCEL_PAYMENT_REASONS.ADMIN) {
+ return Localize.translateLocal('iou.adminCanceledRequest', {amount});
+ }
const submitterDisplayName = getDisplayNameForParticipant(report?.ownerAccountID, true) ?? '';
- const amount = CurrencyUtils.convertToDisplayString(report?.total ?? 0, report?.currency);
return Localize.translateLocal('iou.canceledRequest', {submitterDisplayName, amount});
}
@@ -1847,9 +1863,13 @@ function getTransactionDetails(transaction: OnyxEntry, createdDateF
* - the current user is the requestor and is not settled yet
* - in case of expense report
* - the current user is the requestor and is not settled yet
- * - or the user is an admin on the policy the expense report is tied to
+ * - the current user is the manager of the report
+ * - or the current user is an admin on the policy the expense report is tied to
+ *
+ * This is used in conjunction with canEditRestrictedField to control editing of specific fields like amount, currency, created, receipt, and distance.
+ * On its own, it only controls allowing/disallowing navigating to the editing pages or showing/hiding the 'Edit' icon on report actions
*/
-function canEditMoneyRequest(reportAction: OnyxEntry, fieldToEdit = ''): boolean {
+function canEditMoneyRequest(reportAction: OnyxEntry): boolean {
const isDeleted = ReportActionsUtils.isDeletedAction(reportAction);
if (isDeleted) {
@@ -1872,52 +1892,76 @@ function canEditMoneyRequest(reportAction: OnyxEntry, fieldToEdit
}
const moneyRequestReport = getReport(String(moneyRequestReportID));
- const isReportSettled = isSettled(moneyRequestReport?.reportID);
- const isApproved = isReportApproved(moneyRequestReport);
- const isAdmin = isExpenseReport(moneyRequestReport) && (getPolicy(moneyRequestReport?.policyID ?? '')?.role ?? '') === CONST.POLICY.ROLE.ADMIN;
const isRequestor = currentUserAccountID === reportAction?.actorAccountID;
- if (isAdmin && !isRequestor && fieldToEdit === CONST.EDIT_REQUEST_FIELD.RECEIPT) {
- return false;
+ if (isIOUReport(moneyRequestReport)) {
+ return isProcessingReport(moneyRequestReport) && isRequestor;
}
- if (isAdmin) {
+ const policy = getPolicy(moneyRequestReport?.policyID ?? '');
+ const isAdmin = policy.role === CONST.POLICY.ROLE.ADMIN;
+ const isManager = currentUserAccountID === moneyRequestReport?.managerID;
+
+ // Admin & managers can always edit coding fields such as tag, category, billable, etc. As long as the report has a state higher than OPEN.
+ if ((isAdmin || isManager) && !isDraftExpenseReport(moneyRequestReport)) {
return true;
}
- return !isApproved && !isReportSettled && isRequestor;
+ return !isReportApproved(moneyRequestReport) && !isSettled(moneyRequestReport?.reportID) && isRequestor;
}
/**
* Checks if the current user can edit the provided property of a money request
*
*/
-function canEditFieldOfMoneyRequest(
- reportAction: OnyxEntry,
- reportID: string,
- fieldToEdit: ValueOf,
- transaction: OnyxEntry,
-): boolean {
+function canEditFieldOfMoneyRequest(reportAction: OnyxEntry, fieldToEdit: ValueOf): boolean {
// A list of fields that cannot be edited by anyone, once a money request has been settled
- const nonEditableFieldsWhenSettled: string[] = [
+ const restrictedFields: string[] = [
CONST.EDIT_REQUEST_FIELD.AMOUNT,
CONST.EDIT_REQUEST_FIELD.CURRENCY,
+ CONST.EDIT_REQUEST_FIELD.MERCHANT,
CONST.EDIT_REQUEST_FIELD.DATE,
CONST.EDIT_REQUEST_FIELD.RECEIPT,
CONST.EDIT_REQUEST_FIELD.DISTANCE,
];
- // Checks if this user has permissions to edit this money request
- if (!canEditMoneyRequest(reportAction, fieldToEdit)) {
- return false; // User doesn't have permission to edit
+ if (!canEditMoneyRequest(reportAction)) {
+ return false;
+ }
+
+ // If we're editing fields such as category, tag, description, etc. the check above should be enough for handling the permission
+ if (!restrictedFields.includes(fieldToEdit)) {
+ return true;
}
- if (!isEmpty(transaction) && fieldToEdit === CONST.EDIT_REQUEST_FIELD.RECEIPT && TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction)) {
+
+ const iouMessage = reportAction?.originalMessage as IOUMessage;
+ const moneyRequestReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouMessage?.IOUReportID}`] ?? ({} as Report);
+ const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${iouMessage?.IOUTransactionID}`] ?? ({} as Transaction);
+
+ if (isSettled(String(moneyRequestReport.reportID)) || isReportApproved(String(moneyRequestReport.reportID))) {
return false;
}
- // Checks if the report is settled
- // Checks if the provided property is a restricted one
- return !isSettled(reportID) || !nonEditableFieldsWhenSettled.includes(fieldToEdit);
+ if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.AMOUNT || fieldToEdit === CONST.EDIT_REQUEST_FIELD.CURRENCY) {
+ if (TransactionUtils.isCardTransaction(transaction)) {
+ return false;
+ }
+
+ if (TransactionUtils.isDistanceRequest(transaction)) {
+ const policy = getPolicy(moneyRequestReport?.reportID ?? '');
+ const isAdmin = isExpenseReport(moneyRequestReport) && policy.role === CONST.POLICY.ROLE.ADMIN;
+ const isManager = isExpenseReport(moneyRequestReport) && currentUserAccountID === moneyRequestReport?.managerID;
+
+ return isAdmin || isManager;
+ }
+ }
+
+ if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.RECEIPT) {
+ const isRequestor = currentUserAccountID === reportAction?.actorAccountID;
+ return !TransactionUtils.isReceiptBeingScanned(transaction) && !TransactionUtils.isDistanceRequest(transaction) && isRequestor;
+ }
+
+ return true;
}
/**
@@ -2057,7 +2101,7 @@ function getReportPreviewMessage(
const formattedAmount = CurrencyUtils.convertToDisplayString(totalAmount, report.currency);
- if (isReportApproved(report) && isGroupPolicy(report)) {
+ if (isReportApproved(report) && isPaidGroupPolicy(report)) {
return Localize.translateLocal('iou.managerApprovedAmount', {
manager: payerName ?? '',
amount: formattedAmount,
@@ -2371,7 +2415,7 @@ function buildOptimisticAddCommentReportAction(text?: string, file?: File): Opti
],
automatic: false,
avatar: allPersonalDetails?.[currentUserAccountID ?? -1]?.avatar ?? UserUtils.getDefaultAvatarURL(currentUserAccountID),
- created: DateUtils.getDBTime(),
+ created: DateUtils.getDBTimeWithSkew(),
message: [
{
translationKey: isAttachment ? CONST.TRANSLATION_KEYS.ATTACHMENT : '',
@@ -2385,6 +2429,7 @@ function buildOptimisticAddCommentReportAction(text?: string, file?: File): Opti
attachmentInfo,
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
shouldShow: true,
+ isOptimisticAction: true,
},
};
}
@@ -2505,6 +2550,10 @@ function buildOptimisticIOUReport(payeeAccountID: number, payerAccountID: number
const formattedTotal = CurrencyUtils.convertToDisplayString(total, currency);
const personalDetails = getPersonalDetailsForAccountID(payerAccountID);
const payerEmail = 'login' in personalDetails ? personalDetails.login : '';
+
+ // When creating a report the participantsAccountIDs and visibleChatMemberAccountIDs are the same
+ const participantsAccountIDs = [payeeAccountID, payerAccountID];
+
return {
type: CONST.REPORT.TYPE.IOU,
cachedTotal: formattedTotal,
@@ -2512,7 +2561,8 @@ function buildOptimisticIOUReport(payeeAccountID: number, payerAccountID: number
currency,
managerID: payerAccountID,
ownerAccountID: payeeAccountID,
- participantAccountIDs: [payeeAccountID, payerAccountID],
+ participantAccountIDs: participantsAccountIDs,
+ visibleChatMemberAccountIDs: participantsAccountIDs,
reportID: generateReportID(),
state: CONST.REPORT.STATE.SUBMITTED,
stateNum: isSendingMoney ? CONST.REPORT.STATE_NUM.SUBMITTED : CONST.REPORT.STATE_NUM.PROCESSING,
@@ -2836,6 +2886,40 @@ function buildOptimisticSubmittedReportAction(amount: number, currency: string,
};
}
+/**
+ * Builds an optimistic REIMBURSEMENTDEQUEUED report action with a randomly generated reportActionID.
+ *
+ */
+function buildOptimisticCancelPaymentReportAction(expenseReportID: string): OptimisticCancelPaymentReportAction {
+ return {
+ actionName: CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTDEQUEUED,
+ actorAccountID: currentUserAccountID,
+ message: [
+ {
+ cancellationReason: CONST.REPORT.CANCEL_PAYMENT_REASONS.ADMIN,
+ expenseReportID,
+ type: CONST.REPORT.MESSAGE.TYPE.COMMENT,
+ text: '',
+ },
+ ],
+ originalMessage: {
+ cancellationReason: CONST.REPORT.CANCEL_PAYMENT_REASONS.ADMIN,
+ expenseReportID,
+ },
+ person: [
+ {
+ style: 'strong',
+ text: currentUserPersonalDetails?.displayName ?? currentUserEmail,
+ type: 'TEXT',
+ },
+ ],
+ reportActionID: NumberUtils.rand64(),
+ shouldShow: true,
+ created: DateUtils.getDBTime(),
+ pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
+ };
+}
+
/**
* Builds an optimistic report preview action with a randomly generated reportActionID.
*
@@ -2875,10 +2959,10 @@ function buildOptimisticReportPreview(
accountID: iouReport?.managerID ?? 0,
// The preview is initially whispered if created with a receipt, so the actor is the current user as well
actorAccountID: hasReceipt ? currentUserAccountID : iouReport?.managerID ?? 0,
+ childReportID: childReportID ?? iouReport?.reportID,
childMoneyRequestCount: 1,
childLastMoneyRequestComment: comment,
childRecentReceiptTransactionIDs: hasReceipt && isNotEmptyObject(transaction) ? {[transaction?.transactionID ?? '']: created} : undefined,
- childReportID,
whisperedToAccountIDs: isReceiptBeingScanned ? [currentUserAccountID ?? -1] : [],
};
}
@@ -3048,7 +3132,9 @@ function buildOptimisticChatReport(
ownerAccountID: ownerAccountID || CONST.REPORT.OWNER_ACCOUNT_ID_FAKE,
parentReportActionID,
parentReportID,
+ // When creating a report the participantsAccountIDs and visibleChatMemberAccountIDs are the same
participantAccountIDs: participantList,
+ visibleChatMemberAccountIDs: participantList,
policyID,
reportID: generateReportID(),
reportName,
@@ -3250,12 +3336,16 @@ function buildOptimisticTaskReport(
description?: string,
policyID: string = CONST.POLICY.OWNER_EMAIL_FAKE,
): OptimisticTaskReport {
+ // When creating a report the participantsAccountIDs and visibleChatMemberAccountIDs are the same
+ const participantsAccountIDs = assigneeAccountID && assigneeAccountID !== ownerAccountID ? [assigneeAccountID] : [];
+
return {
reportID: generateReportID(),
reportName: title,
description,
ownerAccountID,
- participantAccountIDs: assigneeAccountID && assigneeAccountID !== ownerAccountID ? [assigneeAccountID] : [],
+ participantAccountIDs: participantsAccountIDs,
+ visibleChatMemberAccountIDs: participantsAccountIDs,
managerID: assigneeAccountID,
type: CONST.REPORT.TYPE.TASK,
parentReportID,
@@ -3717,6 +3807,7 @@ function canRequestMoney(report: OnyxEntry, policy: OnyxEntry, o
if (isOwnExpenseReport && PolicyUtils.isPaidGroupPolicy(policy)) {
return isDraftExpenseReport(report);
}
+
return (isOwnExpenseReport || isIOUReport(report)) && !isReportApproved(report) && !isSettled(report?.reportID);
}
@@ -3885,6 +3976,13 @@ function getAddWorkspaceRoomOrChatReportErrors(report: OnyxEntry): Recor
function canUserPerformWriteAction(report: OnyxEntry) {
const reportErrors = getAddWorkspaceRoomOrChatReportErrors(report);
+ // If the Money Request report is marked for deletion, let us prevent any further write action.
+ if (isMoneyRequestReport(report)) {
+ const parentReportAction = ReportActionsUtils.getReportAction(report?.parentReportID ?? '', report?.parentReportActionID ?? '');
+ if (parentReportAction?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE) {
+ return false;
+ }
+ }
return !isArchivedRoom(report) && isEmptyObject(reportErrors) && report && isAllowedToComment(report) && !isAnonymousUser;
}
@@ -4064,6 +4162,11 @@ function getTaskAssigneeChatOnyxData(
value: optimisticAssigneeReport,
},
);
+ successData.push({
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${assigneeChatReportID}`,
+ value: {[optimisticAssigneeAddComment.reportAction.reportActionID ?? '']: {isOptimisticAction: null}},
+ });
failureData.push({
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${assigneeChatReportID}`,
@@ -4082,6 +4185,8 @@ function getTaskAssigneeChatOnyxData(
/**
* Returns an array of the participants Ids of a report
+ *
+ * @deprecated Use getVisibleMemberIDs instead
*/
function getParticipantsIDs(report: OnyxEntry): number[] {
if (!report) {
@@ -4099,6 +4204,25 @@ function getParticipantsIDs(report: OnyxEntry): number[] {
return participants;
}
+/**
+ * Returns an array of the visible member accountIDs for a report*
+ */
+function getVisibleMemberIDs(report: OnyxEntry): number[] {
+ if (!report) {
+ return [];
+ }
+
+ const visibleChatMemberAccountIDs = report.visibleChatMemberAccountIDs ?? [];
+
+ // Build participants list for IOU/expense reports
+ if (isMoneyRequestReport(report)) {
+ const onlyTruthyValues = [report.managerID, report.ownerAccountID, ...visibleChatMemberAccountIDs].filter(Boolean) as number[];
+ const onlyUnique = [...new Set([...onlyTruthyValues])];
+ return onlyUnique;
+ }
+ return visibleChatMemberAccountIDs;
+}
+
/**
* Return iou report action display message
*/
@@ -4118,17 +4242,22 @@ function getIOUReportActionDisplayMessage(reportAction: OnyxEntry)
const formattedAmount = CurrencyUtils.convertToDisplayString(amount, currency) ?? '';
const payerName = isExpenseReport(iouReport) ? getPolicyName(iouReport) : getDisplayNameForParticipant(iouReport?.managerID, true);
- switch (originalMessage.paymentType) {
- case CONST.IOU.PAYMENT_TYPE.ELSEWHERE:
- translationKey = 'iou.paidElsewhereWithAmount';
- break;
- case CONST.IOU.PAYMENT_TYPE.EXPENSIFY:
- case CONST.IOU.PAYMENT_TYPE.VBBA:
- translationKey = 'iou.paidWithExpensifyWithAmount';
- break;
- default:
- translationKey = 'iou.payerPaidAmount';
- break;
+ // If the payment was cancelled, show the "Owes" message
+ if (!isSettled(IOUReportID)) {
+ translationKey = 'iou.payerOwesAmount';
+ } else {
+ switch (originalMessage.paymentType) {
+ case CONST.IOU.PAYMENT_TYPE.ELSEWHERE:
+ translationKey = 'iou.paidElsewhereWithAmount';
+ break;
+ case CONST.IOU.PAYMENT_TYPE.EXPENSIFY:
+ case CONST.IOU.PAYMENT_TYPE.VBBA:
+ translationKey = 'iou.paidWithExpensifyWithAmount';
+ break;
+ default:
+ translationKey = 'iou.payerPaidAmount';
+ break;
+ }
}
return Localize.translateLocal(translationKey, {amount: formattedAmount, payer: payerName ?? ''});
}
@@ -4202,7 +4331,8 @@ function hasSmartscanError(reportActions: ReportAction[]) {
if (!ReportActionsUtils.isSplitBillAction(action) && !ReportActionsUtils.isReportPreviewAction(action)) {
return false;
}
- const isReportPreviewError = ReportActionsUtils.isReportPreviewAction(action) && hasMissingSmartscanFields(ReportActionsUtils.getIOUReportIDFromReportActionPreview(action));
+ const IOUReportID = ReportActionsUtils.getIOUReportIDFromReportActionPreview(action);
+ const isReportPreviewError = ReportActionsUtils.isReportPreviewAction(action) && hasMissingSmartscanFields(IOUReportID) && !isSettled(IOUReportID);
const transactionID = (action.originalMessage as IOUMessage).IOUTransactionID ?? '0';
const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? {};
const isSplitBillError = ReportActionsUtils.isSplitBillAction(action) && TransactionUtils.hasMissingSmartscanFields(transaction as Transaction);
@@ -4243,6 +4373,14 @@ function navigateToPrivateNotes(report: Report, session: Session) {
Navigation.navigate(ROUTES.PRIVATE_NOTES_LIST.getRoute(report.reportID));
}
+/**
+ * Checks if thread replies should be displayed
+ */
+function shouldDisplayThreadReplies(reportAction: ReportAction, reportID: string): boolean {
+ const hasReplies = (reportAction.childVisibleActionCount ?? 0) > 0;
+ return hasReplies && !!reportAction.childCommenterCount && !isThreadFirstChat(reportAction, reportID);
+}
+
/**
* Disable reply in thread action if:
*
@@ -4309,15 +4447,16 @@ export {
formatReportLastMessageText,
chatIncludesConcierge,
isPolicyExpenseChat,
+ isGroupPolicy,
+ isPaidGroupPolicy,
isControlPolicyExpenseChat,
isControlPolicyExpenseReport,
- isGroupPolicyExpenseChat,
- isGroupPolicyExpenseReport,
+ isPaidGroupPolicyExpenseChat,
+ isPaidGroupPolicyExpenseReport,
getIconsForParticipants,
getIcons,
getRoomWelcomeMessage,
getDisplayNamesWithTooltips,
- getDisplayNamesStringFromTooltips,
getReportName,
getReport,
getReportNotificationPreference,
@@ -4345,6 +4484,7 @@ export {
buildOptimisticIOUReportAction,
buildOptimisticReportPreview,
buildOptimisticModifiedExpenseReportAction,
+ buildOptimisticCancelPaymentReportAction,
updateReportPreview,
buildOptimisticTaskReportAction,
buildOptimisticAddCommentReportAction,
@@ -4417,6 +4557,7 @@ export {
getTransactionDetails,
getTaskAssigneeChatOnyxData,
getParticipantsIDs,
+ getVisibleMemberIDs,
canEditMoneyRequest,
canEditFieldOfMoneyRequest,
buildTransactionThread,
@@ -4440,7 +4581,8 @@ export {
canEditWriteCapability,
hasSmartscanError,
shouldAutoFocusOnKeyPress,
+ shouldDisplayThreadReplies,
shouldDisableThread,
};
-export type {ExpenseOriginalMessage, OptionData, OptimisticChatReport};
+export type {ExpenseOriginalMessage, OptionData, OptimisticChatReport, OptimisticCreatedReportAction};
diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts
index db16cf5cb552..6e46ec320066 100644
--- a/src/libs/SidebarUtils.ts
+++ b/src/libs/SidebarUtils.ts
@@ -127,10 +127,10 @@ function getOrderedReportIDs(
[currentReportId, allReports, betas, policies, priorityMode, allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentReportId}`]?.length || 1],
(key, value: unknown) => {
/**
- * Exclude 'participantAccountIDs', 'participants' and 'lastMessageText' not to overwhelm a cached key value with huge data,
+ * Exclude some properties not to overwhelm a cached key value with huge data,
* which we don't need to store in a cacheKey
*/
- if (key === 'participantAccountIDs' || key === 'participants' || key === 'lastMessageText') {
+ if (key === 'participantAccountIDs' || key === 'participants' || key === 'lastMessageText' || key === 'visibleChatMemberAccountIDs') {
return undefined;
}
@@ -276,6 +276,7 @@ function getOptionData(
isExpenseRequest: false,
isWaitingOnBankAccount: false,
isAllowedToComment: true,
+ isDeletedParentAction: false,
};
const participantPersonalDetailList: PersonalDetails[] = Object.values(OptionsListUtils.getPersonalDetailsForAccountIDs(report.participantAccountIDs ?? [], personalDetails));
const personalDetail = participantPersonalDetailList[0] ?? {};
@@ -304,13 +305,14 @@ function getOptionData(
result.isPinned = report.isPinned;
result.iouReportID = report.iouReportID;
result.keyForList = String(report.reportID);
- result.tooltipText = ReportUtils.getReportParticipantsTitle(report.participantAccountIDs ?? []);
+ result.tooltipText = ReportUtils.getReportParticipantsTitle(report.visibleChatMemberAccountIDs ?? []);
result.hasOutstandingChildRequest = report.hasOutstandingChildRequest;
result.parentReportID = report.parentReportID ?? '';
result.isWaitingOnBankAccount = report.isWaitingOnBankAccount;
result.notificationPreference = report.notificationPreference;
result.isAllowedToComment = ReportUtils.canUserPerformWriteAction(report);
result.chatType = report.chatType;
+ result.isDeletedParentAction = report.isDeletedParentAction;
const hasMultipleParticipants = participantPersonalDetailList.length > 1 || result.isChatRoom || result.isPolicyExpenseChat || ReportUtils.isExpenseReport(report);
const subtitle = ReportUtils.getChatRoomSubtitle(report);
diff --git a/src/libs/UserUtils.ts b/src/libs/UserUtils.ts
index 653acfa36216..6ec386679a32 100644
--- a/src/libs/UserUtils.ts
+++ b/src/libs/UserUtils.ts
@@ -106,7 +106,7 @@ function getDefaultAvatar(accountID = -1, avatarURL?: string): IconAsset {
// But the avatar link still corresponds to the original ID-generated link. So we extract the SVG image number from the backend's link instead of using the user ID directly
let accountIDHashBucket: AvatarRange;
if (avatarURL) {
- const match = avatarURL.match(/(default-avatar_)(\d+)(?=\.)/);
+ const match = avatarURL.match(/(default-avatar_|avatar_)(\d+)(?=\.)/);
const lastDigit = match && parseInt(match[2], 10);
accountIDHashBucket = lastDigit as AvatarRange;
} else {
diff --git a/src/libs/ValidationUtils.ts b/src/libs/ValidationUtils.ts
index 4b973d95d136..9ba11fb16d6a 100644
--- a/src/libs/ValidationUtils.ts
+++ b/src/libs/ValidationUtils.ts
@@ -1,4 +1,3 @@
-import {parsePhoneNumber} from 'awesome-phonenumber';
import {addYears, endOfMonth, format, isAfter, isBefore, isSameDay, isValid, isWithinInterval, parse, parseISO, startOfDay, subYears} from 'date-fns';
import {URL_REGEX_WITH_REQUIRED_PROTOCOL} from 'expensify-common/lib/Url';
import isDate from 'lodash/isDate';
@@ -10,6 +9,7 @@ import type * as OnyxCommon from '@src/types/onyx/OnyxCommon';
import * as CardUtils from './CardUtils';
import DateUtils from './DateUtils';
import * as LoginUtils from './LoginUtils';
+import {parsePhoneNumber} from './PhoneNumber';
import StringUtils from './StringUtils';
/**
@@ -35,7 +35,7 @@ function validateCardNumber(value: string): boolean {
* Validating that this is a valid address (PO boxes are not allowed)
*/
function isValidAddress(value: string): boolean {
- if (!CONST.REGEX.ANY_VALUE.test(value)) {
+ if (!CONST.REGEX.ANY_VALUE.test(value) || value.match(CONST.REGEX.EMOJIS)) {
return false;
}
@@ -306,6 +306,13 @@ function isValidRoutingNumber(routingNumber: string): boolean {
return false;
}
+/**
+ * Checks that the provided name doesn't contain any emojis
+ */
+function isValidCompanyName(name: string) {
+ return !name.match(CONST.REGEX.EMOJIS);
+}
+
/**
* Checks that the provided name doesn't contain any commas or semicolons
*/
@@ -317,7 +324,8 @@ function isValidDisplayName(name: string): boolean {
* Checks that the provided legal name doesn't contain special characters
*/
function isValidLegalName(name: string): boolean {
- return CONST.REGEX.ALPHABETIC_AND_LATIN_CHARS.test(name);
+ const hasAccentedChars = Boolean(name.match(CONST.REGEX.ACCENT_LATIN_CHARS));
+ return CONST.REGEX.ALPHABETIC_AND_LATIN_CHARS.test(name) && !hasAccentedChars;
}
/**
@@ -451,6 +459,7 @@ export {
isValidRoomName,
isValidTaxID,
isValidValidateCode,
+ isValidCompanyName,
isValidDisplayName,
isValidLegalName,
doesContainReservedWord,
diff --git a/src/libs/ValueUtils.ts b/src/libs/ValueUtils.ts
new file mode 100644
index 000000000000..002a8fb347d6
--- /dev/null
+++ b/src/libs/ValueUtils.ts
@@ -0,0 +1,4 @@
+const getReturnValue = (value: ((...p: P) => T) | T, ...p: P) => (typeof value === 'function' ? (value as (...p: P) => T)(...p) : value);
+const getFirstValue = (value: T | [T]) => (Array.isArray(value) ? value[0] : value);
+
+export {getReturnValue, getFirstValue};
diff --git a/src/libs/ViolationsUtils.ts b/src/libs/ViolationsUtils.ts
index 748f0ed86b7f..2637686e726b 100644
--- a/src/libs/ViolationsUtils.ts
+++ b/src/libs/ViolationsUtils.ts
@@ -1,7 +1,9 @@
import reject from 'lodash/reject';
import Onyx from 'react-native-onyx';
+import type {TranslationPaths} from '@src/languages/types';
import ONYXKEYS from '@src/ONYXKEYS';
import type {PolicyCategories, PolicyTags, Transaction, TransactionViolation} from '@src/types/onyx';
+import type {Phrase, PhraseParameters} from './Localize';
const ViolationsUtils = {
/**
@@ -80,6 +82,104 @@ const ViolationsUtils = {
value: newTransactionViolations,
};
},
+ /**
+ * Gets the translated message for each violation type.
+ *
+ * Necessary because `translate` throws a type error if you attempt to pass it a template strings, when the
+ * possible values could be either translation keys that resolve to strings or translation keys that resolve to
+ * functions.
+ */
+ getViolationTranslation(
+ violation: TransactionViolation,
+ translate: (phraseKey: TKey, ...phraseParameters: PhraseParameters>) => string,
+ ): string {
+ switch (violation.name) {
+ case 'allTagLevelsRequired':
+ return translate('violations.allTagLevelsRequired');
+ case 'autoReportedRejectedExpense':
+ return translate('violations.autoReportedRejectedExpense', {
+ rejectedBy: violation.data?.rejectedBy ?? '',
+ rejectReason: violation.data?.rejectReason ?? '',
+ });
+ case 'billableExpense':
+ return translate('violations.billableExpense');
+ case 'cashExpenseWithNoReceipt':
+ return translate('violations.cashExpenseWithNoReceipt', {amount: violation.data?.amount ?? ''});
+ case 'categoryOutOfPolicy':
+ return translate('violations.categoryOutOfPolicy');
+ case 'conversionSurcharge':
+ return translate('violations.conversionSurcharge', {surcharge: violation.data?.surcharge});
+ case 'customUnitOutOfPolicy':
+ return translate('violations.customUnitOutOfPolicy');
+ case 'duplicatedTransaction':
+ return translate('violations.duplicatedTransaction');
+ case 'fieldRequired':
+ return translate('violations.fieldRequired');
+ case 'futureDate':
+ return translate('violations.futureDate');
+ case 'invoiceMarkup':
+ return translate('violations.invoiceMarkup', {invoiceMarkup: violation.data?.invoiceMarkup});
+ case 'maxAge':
+ return translate('violations.maxAge', {maxAge: violation.data?.maxAge ?? 0});
+ case 'missingCategory':
+ return translate('violations.missingCategory');
+ case 'missingComment':
+ return translate('violations.missingComment');
+ case 'missingTag':
+ return translate('violations.missingTag', {tagName: violation.data?.tagName});
+ case 'modifiedAmount':
+ return translate('violations.modifiedAmount');
+ case 'modifiedDate':
+ return translate('violations.modifiedDate');
+ case 'nonExpensiworksExpense':
+ return translate('violations.nonExpensiworksExpense');
+ case 'overAutoApprovalLimit':
+ return translate('violations.overAutoApprovalLimit', {formattedLimitAmount: violation.data?.formattedLimitAmount ?? ''});
+ case 'overCategoryLimit':
+ return translate('violations.overCategoryLimit', {categoryLimit: violation.data?.categoryLimit ?? ''});
+ case 'overLimit':
+ return translate('violations.overLimit', {amount: violation.data?.amount ?? ''});
+ case 'overLimitAttendee':
+ return translate('violations.overLimitAttendee', {amount: violation.data?.amount ?? ''});
+ case 'perDayLimit':
+ return translate('violations.perDayLimit', {limit: violation.data?.limit ?? ''});
+ case 'receiptNotSmartScanned':
+ return translate('violations.receiptNotSmartScanned');
+ case 'receiptRequired':
+ return translate('violations.receiptRequired', {
+ amount: violation.data?.amount ?? '0',
+ category: violation.data?.category ?? '',
+ });
+ case 'rter':
+ return translate('violations.rter', {
+ brokenBankConnection: violation.data?.brokenBankConnection ?? false,
+ isAdmin: violation.data?.isAdmin ?? false,
+ email: violation.data?.email,
+ isTransactionOlderThan7Days: Boolean(violation.data?.isTransactionOlderThan7Days),
+ member: violation.data?.member,
+ });
+ case 'smartscanFailed':
+ return translate('violations.smartscanFailed');
+ case 'someTagLevelsRequired':
+ return translate('violations.someTagLevelsRequired');
+ case 'tagOutOfPolicy':
+ return translate('violations.tagOutOfPolicy', {tagName: violation.data?.tagName});
+ case 'taxAmountChanged':
+ return translate('violations.taxAmountChanged');
+ case 'taxOutOfPolicy':
+ return translate('violations.taxOutOfPolicy', {taxName: violation.data?.taxName});
+ case 'taxRateChanged':
+ return translate('violations.taxRateChanged');
+ case 'taxRequired':
+ return translate('violations.taxRequired');
+ default:
+ // The interpreter should never get here because the switch cases should be exhaustive.
+ // If typescript is showing an error on the assertion below it means the switch statement is out of
+ // sync with the `ViolationNames` type, and one or the other needs to be updated.
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
+ return violation.name as never;
+ }
+ },
};
export default ViolationsUtils;
diff --git a/src/libs/__mocks__/Permissions.ts b/src/libs/__mocks__/Permissions.ts
index 759392bde2c6..b175e9f40efc 100644
--- a/src/libs/__mocks__/Permissions.ts
+++ b/src/libs/__mocks__/Permissions.ts
@@ -11,5 +11,4 @@ import type Beta from '@src/types/onyx/Beta';
export default {
...jest.requireActual('../Permissions'),
canUseDefaultRooms: (betas: Beta[]) => betas.includes(CONST.BETAS.DEFAULT_ROOMS),
- canUsePolicyRooms: (betas: Beta[]) => betas.includes(CONST.BETAS.POLICY_ROOMS),
};
diff --git a/src/libs/actions/App.ts b/src/libs/actions/App.ts
index f88bfe09e516..768dc530cc51 100644
--- a/src/libs/actions/App.ts
+++ b/src/libs/actions/App.ts
@@ -7,6 +7,7 @@ import Onyx from 'react-native-onyx';
import type {ValueOf} from 'type-fest';
import * as API from '@libs/API';
import * as Browser from '@libs/Browser';
+import DateUtils from '@libs/DateUtils';
import Log from '@libs/Log';
import getCurrentUrl from '@libs/Navigation/currentUrl';
import Navigation from '@libs/Navigation/Navigation';
@@ -158,7 +159,7 @@ function getPolicyParamsForOpenOrReconnect(): Promise = {
+ const defaultData = {
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
@@ -166,14 +167,7 @@ function getOnyxDataForOpenOrReconnect(isOpenApp = false): OnyxData {
value: true,
},
],
- successData: [
- {
- onyxMethod: Onyx.METHOD.MERGE,
- key: ONYXKEYS.IS_LOADING_REPORT_DATA,
- value: false,
- },
- ],
- failureData: [
+ finallyData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.IS_LOADING_REPORT_DATA,
@@ -193,16 +187,8 @@ function getOnyxDataForOpenOrReconnect(isOpenApp = false): OnyxData {
value: true,
},
],
- successData: [
- ...defaultData.successData,
- {
- onyxMethod: Onyx.METHOD.MERGE,
- key: ONYXKEYS.IS_LOADING_APP,
- value: false,
- },
- ],
- failureData: [
- ...defaultData.failureData,
+ finallyData: [
+ ...defaultData.finallyData,
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.IS_LOADING_APP,
@@ -296,12 +282,12 @@ function finalReconnectAppAfterActivatingReliableUpdates(): Promise {
+function getMissingOnyxUpdates(updateIDFrom = 0, updateIDTo: number | string = 0): Promise {
console.debug(`[OnyxUpdates] Fetching missing updates updateIDFrom: ${updateIDFrom} and updateIDTo: ${updateIDTo}`);
type GetMissingOnyxMessagesParams = {
updateIDFrom: number;
- updateIDTo: number;
+ updateIDTo: number | string;
};
const parameters: GetMissingOnyxMessagesParams = {
@@ -412,7 +398,7 @@ function setUpPoliciesAndNavigate(session: OnyxEntry) {
return;
}
if (!isLoggingInAsNewUser && exitTo) {
- Navigation.isNavigationReady()
+ Navigation.waitForProtectedRoutes()
.then(() => {
// We must call goBack() to remove the /transition route from history
Navigation.goBack(ROUTES.HOME);
@@ -448,6 +434,8 @@ function openProfile(personalDetails: OnyxTypes.PersonalDetails) {
};
}
+ newTimezoneData = DateUtils.formatToSupportedTimezone(newTimezoneData);
+
type OpenProfileParams = {
timezone: string;
};
diff --git a/src/libs/actions/CanvasSize.js b/src/libs/actions/CanvasSize.ts
similarity index 92%
rename from src/libs/actions/CanvasSize.js
rename to src/libs/actions/CanvasSize.ts
index b313763131b9..8e0a155f25eb 100644
--- a/src/libs/actions/CanvasSize.js
+++ b/src/libs/actions/CanvasSize.ts
@@ -11,12 +11,12 @@ function retrieveMaxCanvasArea() {
// More information at: https://github.com/jhildenbiddle/canvas-size/issues/13
canvasSize
.maxArea({
- max: Browser.isMobile() ? 8192 : null,
+ max: Browser.isMobile() ? 8192 : undefined,
usePromise: true,
useWorker: false,
})
.then(() => ({
- onSuccess: (width, height) => {
+ onSuccess: (width: number, height: number) => {
Onyx.merge(ONYXKEYS.MAX_CANVAS_AREA, width * height);
},
}));
diff --git a/src/libs/actions/Card.js b/src/libs/actions/Card.js
deleted file mode 100644
index 68642bd8fdf1..000000000000
--- a/src/libs/actions/Card.js
+++ /dev/null
@@ -1,176 +0,0 @@
-import Onyx from 'react-native-onyx';
-import * as API from '@libs/API';
-import * as Localize from '@libs/Localize';
-import CONST from '@src/CONST';
-import ONYXKEYS from '@src/ONYXKEYS';
-
-/**
- * @param {Number} cardID
- */
-function reportVirtualExpensifyCardFraud(cardID) {
- API.write(
- 'ReportVirtualExpensifyCardFraud',
- {
- cardID,
- },
- {
- optimisticData: [
- {
- onyxMethod: Onyx.METHOD.MERGE,
- key: ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD,
- value: {
- isLoading: true,
- },
- },
- ],
- successData: [
- {
- onyxMethod: Onyx.METHOD.MERGE,
- key: ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD,
- value: {
- isLoading: false,
- },
- },
- ],
- failureData: [
- {
- onyxMethod: Onyx.METHOD.MERGE,
- key: ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD,
- value: {
- isLoading: false,
- },
- },
- ],
- },
- );
-}
-
-/**
- * Call the API to deactivate the card and request a new one
- * @param {String} cardId - id of the card that is going to be replaced
- * @param {String} reason - reason for replacement ('damaged' | 'stolen')
- */
-function requestReplacementExpensifyCard(cardId, reason) {
- API.write(
- 'RequestReplacementExpensifyCard',
- {
- cardId,
- reason,
- },
- {
- optimisticData: [
- {
- onyxMethod: Onyx.METHOD.MERGE,
- key: ONYXKEYS.FORMS.REPORT_PHYSICAL_CARD_FORM,
- value: {
- isLoading: true,
- errors: null,
- },
- },
- ],
- successData: [
- {
- onyxMethod: Onyx.METHOD.MERGE,
- key: ONYXKEYS.FORMS.REPORT_PHYSICAL_CARD_FORM,
- value: {
- isLoading: false,
- },
- },
- ],
- failureData: [
- {
- onyxMethod: Onyx.METHOD.MERGE,
- key: ONYXKEYS.FORMS.REPORT_PHYSICAL_CARD_FORM,
- value: {
- isLoading: false,
- },
- },
- ],
- },
- );
-}
-
-/**
- * Activates the physical Expensify card based on the last four digits of the card number
- *
- * @param {String} cardLastFourDigits
- * @param {Number} cardID
- */
-function activatePhysicalExpensifyCard(cardLastFourDigits, cardID) {
- API.write(
- 'ActivatePhysicalExpensifyCard',
- {cardLastFourDigits, cardID},
- {
- optimisticData: [
- {
- onyxMethod: Onyx.METHOD.MERGE,
- key: ONYXKEYS.CARD_LIST,
- value: {
- [cardID]: {
- errors: null,
- isLoading: true,
- },
- },
- },
- ],
- successData: [
- {
- onyxMethod: Onyx.METHOD.MERGE,
- key: ONYXKEYS.CARD_LIST,
- value: {
- [cardID]: {
- isLoading: false,
- },
- },
- },
- ],
- failureData: [
- {
- onyxMethod: Onyx.METHOD.MERGE,
- key: ONYXKEYS.CARD_LIST,
- value: {
- [cardID]: {
- isLoading: false,
- },
- },
- },
- ],
- },
- );
-}
-
-/**
- * Clears errors for a specific cardID
- *
- * @param {Number} cardID
- */
-function clearCardListErrors(cardID) {
- Onyx.merge(ONYXKEYS.CARD_LIST, {[cardID]: {errors: null, isLoading: false}});
-}
-
-/**
- * Makes an API call to get virtual card details (pan, cvv, expiration date, address)
- * This function purposefully uses `makeRequestWithSideEffects` method. For security reason
- * card details cannot be persisted in Onyx and have to be asked for each time a user want's to
- * reveal them.
- *
- * @param {String} cardID - virtual card ID
- *
- * @returns {Promise