diff --git a/.eslintignore b/.eslintignore index 3d966d096add..5c4b73d8a682 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,6 +3,7 @@ .github/actions/**/index.js *.config.js **/.eslintrc.js +**/.eslintrc.changed.js **/node_modules/** **/dist/** android/**/build/** diff --git a/.eslintrc.changed.js b/.eslintrc.changed.js new file mode 100644 index 000000000000..c279c3e67a51 --- /dev/null +++ b/.eslintrc.changed.js @@ -0,0 +1,10 @@ +module.exports = { + plugins: ['@typescript-eslint', 'deprecation'], + parser: '@typescript-eslint/parser', + parserOptions: { + project: './tsconfig.json', + }, + rules: { + 'deprecation/deprecation': 'error', + }, +}; diff --git a/.eslintrc.pr.js b/.eslintrc.pr.js deleted file mode 100644 index 63e058bf6005..000000000000 --- a/.eslintrc.pr.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - extends: './.eslintrc', - plugins: ['deprecation'], - rules: { - 'deprecation/deprecation': 'error', - }, -}; diff --git a/.github/workflows/lint-changed.yml b/.github/workflows/lint-changed.yml new file mode 100644 index 000000000000..ddb640bfe9cf --- /dev/null +++ b/.github/workflows/lint-changed.yml @@ -0,0 +1,32 @@ +name: Changed files ESLint check + +on: + workflow_call: + pull_request: + types: [opened, synchronize] + branches-ignore: [staging, production] + paths: ['**.js', '**.ts', '**.tsx', '**.json', '**.mjs', '**.cjs', 'config/.editorconfig', '.watchmanconfig', '.imgbotconfig'] + +concurrency: + group: ${{ github.ref == 'refs/heads/main' && format('{0}-{1}', github.ref, github.sha) || github.ref }}-changed-lint + cancel-in-progress: true + +jobs: + lint-changed: + name: Changed files ESLint check + if: ${{ github.actor != 'OSBotify' || github.event_name == 'workflow_call' }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: ./.github/actions/composite/setupNode + + - name: Run ESLint to check for deprecation warnings + run: | + # This will just fetch the latest commit from main + git fetch origin main --no-tags --depth=1 + + # shellcheck disable=SC2046 + npm run lint-changed diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 4cf5c3eb287f..af6bfa17fb6e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,4 +1,4 @@ -name: Lint code +name: ESLint check on: workflow_call: @@ -13,7 +13,7 @@ concurrency: jobs: lint: - name: Run ESLint + name: ESLint check if: ${{ github.actor != 'OSBotify' || github.event_name == 'workflow_call' }} runs-on: ubuntu-latest steps: @@ -27,21 +27,3 @@ jobs: run: npm run lint env: CI: true - - - name: Run ESLint with stricter checks on changed files - run: | - # shellcheck disable=SC2046 - npx eslint --config ./.eslintrc.pr.js $(git diff --diff-filter=AM --name-only main -- "*.js" "*.ts" "*.tsx") - - - name: Verify there's no Prettier diff - run: | - npm run prettier -- --loglevel silent - if ! git diff --name-only --exit-code; then - # shellcheck disable=SC2016 - echo 'Error: Prettier diff detected! Please run `npm run prettier` and commit the changes.' - exit 1 - fi - - - name: Run unused style searcher - shell: bash - run: ./.github/scripts/findUnusedKeys.sh diff --git a/.github/workflows/preDeploy.yml b/.github/workflows/preDeploy.yml index e5ccdfa53076..796468170275 100644 --- a/.github/workflows/preDeploy.yml +++ b/.github/workflows/preDeploy.yml @@ -13,6 +13,9 @@ jobs: lint: uses: ./.github/workflows/lint.yml + prettier: + uses: ./.github/workflows/prettier.yml + test: uses: ./.github/workflows/test.yml diff --git a/.github/workflows/prettier.yml b/.github/workflows/prettier.yml new file mode 100644 index 000000000000..d5cff2d9b838 --- /dev/null +++ b/.github/workflows/prettier.yml @@ -0,0 +1,37 @@ +name: Prettier check + +on: + workflow_call: + pull_request: + types: [opened, synchronize] + branches-ignore: [staging, production] + paths: ['**.js', '**.ts', '**.tsx', '**.json', '**.mjs', '**.cjs', 'config/.editorconfig', '.watchmanconfig', '.imgbotconfig'] + +concurrency: + group: ${{ github.ref == 'refs/heads/main' && format('{0}-{1}', github.ref, github.sha) || github.ref }}-prettier + cancel-in-progress: true + +jobs: + prettier: + name: Prettier check + if: ${{ github.actor != 'OSBotify' || github.event_name == 'workflow_call' }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: ./.github/actions/composite/setupNode + + - name: Verify there's no Prettier diff + run: | + npm run prettier -- --loglevel silent + if ! git diff --name-only --exit-code; then + # shellcheck disable=SC2016 + echo 'Error: Prettier diff detected! Please run `npm run prettier` and commit the changes.' + exit 1 + fi + + - name: Run unused style searcher + shell: bash + run: ./.github/scripts/findUnusedKeys.sh diff --git a/android/app/build.gradle b/android/app/build.gradle index 62d4c09179df..7634aea8f5f9 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -110,8 +110,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1009003402 - versionName "9.0.34-2" + versionCode 1009003601 + versionName "9.0.36-1" // Supported language variants must be declared here to avoid from being removed during the compilation. // This also helps us to not include unnecessary language variants in the APK. resConfigs "en", "es" diff --git a/android/app/src/main/java/com/expensify/chat/MainApplication.kt b/android/app/src/main/java/com/expensify/chat/MainApplication.kt index 26a28d9955a0..2cc8b7780253 100644 --- a/android/app/src/main/java/com/expensify/chat/MainApplication.kt +++ b/android/app/src/main/java/com/expensify/chat/MainApplication.kt @@ -8,6 +8,7 @@ import android.database.CursorWindow import android.os.Process import androidx.multidex.MultiDexApplication import com.expensify.chat.bootsplash.BootSplashPackage +import com.expensify.chat.shortcutManagerModule.ShortcutManagerPackage import com.facebook.react.PackageList import com.facebook.react.ReactApplication import com.facebook.react.ReactNativeHost @@ -29,6 +30,7 @@ class MainApplication : MultiDexApplication(), ReactApplication { PackageList(this).packages.apply { // Packages that cannot be autolinked yet can be added manually here, for example: // add(MyReactNativePackage()); + add(ShortcutManagerPackage()) add(BootSplashPackage()) add(ExpensifyAppPackage()) add(RNTextInputResetPackage()) diff --git a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java index 8eff32dedf76..b950921a0cd5 100644 --- a/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java +++ b/android/app/src/main/java/com/expensify/chat/customairshipextender/CustomNotificationProvider.java @@ -8,6 +8,7 @@ import android.app.NotificationChannelGroup; import android.app.NotificationManager; import android.content.Context; +import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.Canvas; @@ -30,10 +31,13 @@ import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationManagerCompat; import androidx.core.app.Person; +import androidx.core.content.pm.ShortcutInfoCompat; +import androidx.core.content.pm.ShortcutManagerCompat; import androidx.core.graphics.drawable.IconCompat; import androidx.versionedparcelable.ParcelUtils; import com.expensify.chat.R; +import com.expensify.chat.shortcutManagerModule.ShortcutManagerUtils; import com.urbanairship.AirshipConfigOptions; import com.urbanairship.json.JsonMap; import com.urbanairship.json.JsonValue; @@ -47,6 +51,7 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; +import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Objects; @@ -205,44 +210,47 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil // Use the formatted alert message from the backend. Otherwise fallback on the message in the Onyx data. String message = alert != null ? alert : messageData.get("message").getList().get(0).getMap().get("text").getString(); - String conversationName = payload.get("roomName") == null ? "" : payload.get("roomName").getString(""); + String roomName = payload.get("roomName") == null ? "" : payload.get("roomName").getString(""); - // create the Person object who sent the latest report comment + // Create the Person object who sent the latest report comment Bitmap personIcon = fetchIcon(context, avatar); builder.setLargeIcon(personIcon); Person person = createMessagePersonObject(IconCompat.createWithBitmap(personIcon), accountID, name); + ShortcutManagerUtils.addDynamicShortcut(context, reportID, name, accountID, personIcon, person); + // Create latest received message object long createdTimeInMillis = getMessageTimeInMillis(messageData.get("created").getString("")); NotificationCompat.MessagingStyle.Message newMessage = new NotificationCompat.MessagingStyle.Message(message, createdTimeInMillis, person); - // Conversational styling should be applied to groups chats, rooms, and any 1:1 chats with more than one notification (ensuring the large profile image is always shown) - if (!conversationName.isEmpty() || hasExistingNotification) { - // Create the messaging style notification builder for this notification, associating it with the person who sent the report comment - NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle(person) - .setGroupConversation(true) - .setConversationTitle(conversationName); + NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle(person); + // Add all conversation messages to the notification, including the last one we just received. + List messages; + if (hasExistingNotification) { + NotificationCompat.MessagingStyle previousStyle = NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification(existingReportNotification.getNotification()); + messages = previousStyle != null ? previousStyle.getMessages() : new ArrayList<>(List.of(recreatePreviousMessage(existingReportNotification))); + } else { + messages = new ArrayList<>(); + } - // Add all conversation messages to the notification, including the last one we just received. - List messages; - if (hasExistingNotification) { - NotificationCompat.MessagingStyle previousStyle = NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification(existingReportNotification.getNotification()); - messages = previousStyle != null ? previousStyle.getMessages() : new ArrayList<>(List.of(recreatePreviousMessage(existingReportNotification))); - } else { - messages = new ArrayList<>(); - } - - // add the last one message we just received. - messages.add(newMessage); + // add the last one message we just received. + messages.add(newMessage); - for (NotificationCompat.MessagingStyle.Message activeMessage : messages) { - messagingStyle.addMessage(activeMessage); - } + for (NotificationCompat.MessagingStyle.Message activeMessage : messages) { + messagingStyle.addMessage(activeMessage); + } - builder.setStyle(messagingStyle); + // Conversational styling should be applied to groups chats, rooms, and any 1:1 chats with more than one notification (ensuring the large profile image is always shown) + if (!roomName.isEmpty()) { + // Create the messaging style notification builder for this notification, associating it with the person who sent the report comment + messagingStyle + .setGroupConversation(true) + .setConversationTitle(roomName); } + builder.setStyle(messagingStyle); + builder.setShortcutId(accountID); // save reportID and person info for future merging builder.addExtras(createMessageExtrasBundle(reportID, person)); diff --git a/android/app/src/main/java/com/expensify/chat/shortcutManagerModule/ShortcutManagerModule.java b/android/app/src/main/java/com/expensify/chat/shortcutManagerModule/ShortcutManagerModule.java new file mode 100644 index 000000000000..fdb6d0ba3b97 --- /dev/null +++ b/android/app/src/main/java/com/expensify/chat/shortcutManagerModule/ShortcutManagerModule.java @@ -0,0 +1,43 @@ +package com.expensify.chat.shortcutManagerModule; + +import static androidx.core.app.NotificationCompat.CATEGORY_MESSAGE; + +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.net.Uri; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.core.app.Person; +import androidx.core.content.pm.ShortcutInfoCompat; +import androidx.core.content.pm.ShortcutManagerCompat; +import androidx.core.graphics.drawable.IconCompat; + +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; + +import java.util.Collections; + +import com.expensify.chat.customairshipextender.CustomNotificationProvider; + +public class ShortcutManagerModule extends ReactContextBaseJavaModule { + private ReactApplicationContext context; + + public ShortcutManagerModule(ReactApplicationContext context) { + super(context); + this.context = context; + } + + @NonNull + @Override + public String getName() { + return "ShortcutManager"; + } + + @ReactMethod + public void removeAllDynamicShortcuts() { + ShortcutManagerUtils.removeAllDynamicShortcuts(context); + } +} diff --git a/android/app/src/main/java/com/expensify/chat/shortcutManagerModule/ShortcutManagerPackage.java b/android/app/src/main/java/com/expensify/chat/shortcutManagerModule/ShortcutManagerPackage.java new file mode 100644 index 000000000000..d28f75592d93 --- /dev/null +++ b/android/app/src/main/java/com/expensify/chat/shortcutManagerModule/ShortcutManagerPackage.java @@ -0,0 +1,29 @@ +package com.expensify.chat.shortcutManagerModule; + +import androidx.annotation.NonNull; + +import com.facebook.react.ReactPackage; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.uimanager.ViewManager; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ShortcutManagerPackage implements ReactPackage { + + @NonNull + @Override + public List createViewManagers(@NonNull ReactApplicationContext reactContext) { + return Collections.emptyList(); + } + + @NonNull + @Override + public List createNativeModules(@NonNull ReactApplicationContext reactContext) { + List modules = new ArrayList<>(); + modules.add(new ShortcutManagerModule(reactContext)); + return modules; + } +} diff --git a/android/app/src/main/java/com/expensify/chat/shortcutManagerModule/ShortcutManagerUtils.java b/android/app/src/main/java/com/expensify/chat/shortcutManagerModule/ShortcutManagerUtils.java new file mode 100644 index 000000000000..5947faaa67c4 --- /dev/null +++ b/android/app/src/main/java/com/expensify/chat/shortcutManagerModule/ShortcutManagerUtils.java @@ -0,0 +1,38 @@ +package com.expensify.chat.shortcutManagerModule; + +import static androidx.core.app.NotificationCompat.CATEGORY_MESSAGE; + +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.net.Uri; + +import androidx.core.app.Person; +import androidx.core.content.pm.ShortcutInfoCompat; +import androidx.core.content.pm.ShortcutManagerCompat; +import androidx.core.graphics.drawable.IconCompat; + +import java.util.Collections; + +public class ShortcutManagerUtils { + public static void removeAllDynamicShortcuts(Context context) { + ShortcutManagerCompat.removeAllDynamicShortcuts(context); + } + + public static void addDynamicShortcut(Context context, long reportID, String name, String accountID, Bitmap personIcon, Person person) { + Intent intent = new Intent(Intent.ACTION_VIEW, + Uri.parse("new-expensify://r/" + reportID)); + + ShortcutInfoCompat shortcutInfo = new ShortcutInfoCompat.Builder(context, accountID) + .setShortLabel(name) + .setLongLabel(name) + .setCategories(Collections.singleton(CATEGORY_MESSAGE)) + .setIntent(intent) + .setLongLived(true) + .setPerson(person) + .setIcon(IconCompat.createWithBitmap(personIcon)) + .build(); + ShortcutManagerCompat.pushDynamicShortcut(context, shortcutInfo); + } + +} diff --git a/assets/images/bookmark.svg b/assets/images/bookmark.svg new file mode 100644 index 000000000000..d7c1a8397b37 --- /dev/null +++ b/assets/images/bookmark.svg @@ -0,0 +1 @@ + diff --git a/assets/images/companyCards/card-amex.svg b/assets/images/companyCards/card-amex.svg new file mode 100644 index 000000000000..5282ca095760 --- /dev/null +++ b/assets/images/companyCards/card-amex.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/companyCards/card-bank_of_america.svg b/assets/images/companyCards/card-bank_of_america.svg new file mode 100644 index 000000000000..684a6a0a28f5 --- /dev/null +++ b/assets/images/companyCards/card-bank_of_america.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/companyCards/card-brex.svg b/assets/images/companyCards/card-brex.svg new file mode 100644 index 000000000000..068c9a054d39 --- /dev/null +++ b/assets/images/companyCards/card-brex.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/companyCards/card-capital_one.svg b/assets/images/companyCards/card-capital_one.svg new file mode 100644 index 000000000000..0a324710ae5d --- /dev/null +++ b/assets/images/companyCards/card-capital_one.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/companyCards/card-chase.svg b/assets/images/companyCards/card-chase.svg new file mode 100644 index 000000000000..511453169813 --- /dev/null +++ b/assets/images/companyCards/card-chase.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/companyCards/card-citi.svg b/assets/images/companyCards/card-citi.svg new file mode 100644 index 000000000000..2d2bf71b1312 --- /dev/null +++ b/assets/images/companyCards/card-citi.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/companyCards/card-expensify.svg b/assets/images/companyCards/card-expensify.svg new file mode 100644 index 000000000000..d6b847d8f74f --- /dev/null +++ b/assets/images/companyCards/card-expensify.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/companyCards/card-mastercard.svg b/assets/images/companyCards/card-mastercard.svg new file mode 100644 index 000000000000..b1a698fe9acc --- /dev/null +++ b/assets/images/companyCards/card-mastercard.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/companyCards/card-other.svg b/assets/images/companyCards/card-other.svg new file mode 100644 index 000000000000..11ff21285626 --- /dev/null +++ b/assets/images/companyCards/card-other.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/companyCards/card-stripe.svg b/assets/images/companyCards/card-stripe.svg new file mode 100644 index 000000000000..e4c874452309 --- /dev/null +++ b/assets/images/companyCards/card-stripe.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/companyCards/card-visa.svg b/assets/images/companyCards/card-visa.svg new file mode 100644 index 000000000000..52d0f727a960 --- /dev/null +++ b/assets/images/companyCards/card-visa.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/companyCards/card-wells_fargo.svg b/assets/images/companyCards/card-wells_fargo.svg new file mode 100644 index 000000000000..66402710de97 --- /dev/null +++ b/assets/images/companyCards/card-wells_fargo.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/user-eye.svg b/assets/images/user-eye.svg new file mode 100644 index 000000000000..2265b4892ded --- /dev/null +++ b/assets/images/user-eye.svg @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/desktop/package-lock.json b/desktop/package-lock.json index 1187b3182187..152ad1a4c5ba 100644 --- a/desktop/package-lock.json +++ b/desktop/package-lock.json @@ -9,7 +9,7 @@ "dependencies": { "electron-context-menu": "^2.3.0", "electron-log": "^4.4.8", - "electron-updater": "^6.3.3", + "electron-updater": "^6.3.4", "mime-types": "^2.1.35", "node-machine-id": "^1.1.12" }, @@ -154,9 +154,9 @@ "integrity": "sha512-QQ4GvrXO+HkgqqEOYbi+DHL7hj5JM+nHi/j+qrN9zeeXVKy8ZABgbu4CnG+BBqDZ2+tbeq9tUC4DZfIWFU5AZA==" }, "node_modules/electron-updater": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.3.3.tgz", - "integrity": "sha512-Kj1u6kfyxUyatnspvKa6qhGn82rMZfUD03WOvCGJ12PyRss/AC8kkYsN9IrJihKTlN8nRwTjZ1JM2UUXoD0KsA==", + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.3.4.tgz", + "integrity": "sha512-uZUo7p1Y53G4tl6Cgw07X1yF8Jlz6zhaL7CQJDZ1fVVkOaBfE2cWtx80avwDVi8jHp+I/FWawrMgTAeCCNIfAg==", "license": "MIT", "dependencies": { "builder-util-runtime": "9.2.5", @@ -165,7 +165,7 @@ "lazy-val": "^1.0.5", "lodash.escaperegexp": "^4.1.2", "lodash.isequal": "^4.5.0", - "semver": "^7.3.8", + "semver": "^7.6.3", "tiny-typed-emitter": "^2.1.0" } }, @@ -276,17 +276,6 @@ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -349,12 +338,10 @@ "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -445,11 +432,6 @@ "engines": { "node": ">=8" } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } }, "dependencies": { @@ -552,9 +534,9 @@ "integrity": "sha512-QQ4GvrXO+HkgqqEOYbi+DHL7hj5JM+nHi/j+qrN9zeeXVKy8ZABgbu4CnG+BBqDZ2+tbeq9tUC4DZfIWFU5AZA==" }, "electron-updater": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.3.3.tgz", - "integrity": "sha512-Kj1u6kfyxUyatnspvKa6qhGn82rMZfUD03WOvCGJ12PyRss/AC8kkYsN9IrJihKTlN8nRwTjZ1JM2UUXoD0KsA==", + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.3.4.tgz", + "integrity": "sha512-uZUo7p1Y53G4tl6Cgw07X1yF8Jlz6zhaL7CQJDZ1fVVkOaBfE2cWtx80avwDVi8jHp+I/FWawrMgTAeCCNIfAg==", "requires": { "builder-util-runtime": "9.2.5", "fs-extra": "^10.1.0", @@ -562,7 +544,7 @@ "lazy-val": "^1.0.5", "lodash.escaperegexp": "^4.1.2", "lodash.isequal": "^4.5.0", - "semver": "^7.3.8", + "semver": "^7.6.3", "tiny-typed-emitter": "^2.1.0" } }, @@ -650,14 +632,6 @@ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, "mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -705,12 +679,9 @@ "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==" }, "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "requires": { - "lru-cache": "^6.0.0" - } + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==" }, "slice-ansi": { "version": "3.0.0", @@ -774,11 +745,6 @@ "modify-filename": "^1.1.0", "path-exists": "^4.0.0" } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } } diff --git a/desktop/package.json b/desktop/package.json index cf3c3f4354b3..6c2158a74978 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -6,7 +6,7 @@ "dependencies": { "electron-context-menu": "^2.3.0", "electron-log": "^4.4.8", - "electron-updater": "^6.3.3", + "electron-updater": "^6.3.4", "mime-types": "^2.1.35", "node-machine-id": "^1.1.12" }, diff --git a/docs/articles/expensify-classic/connections/Deel.md b/docs/articles/expensify-classic/connections/Deel.md new file mode 100644 index 000000000000..12e616d9657f --- /dev/null +++ b/docs/articles/expensify-classic/connections/Deel.md @@ -0,0 +1,35 @@ +--- +title: Deel Integration +description: Automatically sync expenses from Expensify to Deel +--- + +# Overview + +This guide is for business clients who want to set up policies and synchronize expenses from Expensify to Deel. This one-way synchronization ensures that Expensify becomes the definitive source for all employee expenses. + +If you are a contractor or employee working for a company using Expensify, please refer to: + +- [Employee Guide to Using Expensify with Deel](https://help.letsdeel.com/hc/en-gb/articles/7123572847761-Employee-s-Guide-to-Using-Expensify-With-Deel) +- [Contractor Guide to Using Expensify with Deel](https://help.letsdeel.com/hc/en-gb/articles/9640208314897-How-Contractors-Can-Use-Expensify-With-Deel) + +## Introduction: + +By integrating Expensify with Deel, you can utilize Expensify’s approval workflows to ensure timely payment through Deel for your team. + +This process involves aligning user profiles and expense policies between Expensify and Deel. Once connected, Deel will scan for approved expenses from matched users included in selected workspaces for integration, allowing Deel to import these expenses for reimbursement. + +This synchronization is one-way. Expenses and receipts logged and approved in Expensify will sync to Deel. Expenses logged in Deel will not sync to Expensify. + +*Please note,* expense syncing is not immediate. For details on how syncing operates, refer to ["How Does Expense Syncing Work?"]([https://example.com](https://help.letsdeel.com/hc/en-gb/articles/5871319525521-How-To-Set-Up-The-Expensify-Integration-On-Deel-For-EOR-Employees-And-Contractors#h_01G25AWSW0KHWBA63C1AZ6X9E9)) + +## Before you begin: + +To establish a connection, make sure you have the following: + +- Deel Organization Manager permissions +- Expensify Admin permissions for policies you wish to integrate with Deel +- A paid Expensify subscription to approve expenses and sync them to Deel + +Expensify Admin permissions can be intricate. Refer to [Expensify’s Introduction to Integration]([https://example.com](https://integrations.expensify.com/Integration-Server/doc/#introduction)) for more details. + +For further steps on integration, consult the [integration guide](https://help.letsdeel.com/hc/en-gb/articles/5871319525521-How-To-Set-Up-The-Expensify-Integration-On-Deel-For-EOR-Employees-And-Contractors). diff --git a/docs/articles/expensify-classic/domains/Claim-And-Verify-A-Domain.md b/docs/articles/expensify-classic/domains/Claim-And-Verify-A-Domain.md index 509961b026e5..ed74224c622e 100644 --- a/docs/articles/expensify-classic/domains/Claim-And-Verify-A-Domain.md +++ b/docs/articles/expensify-classic/domains/Claim-And-Verify-A-Domain.md @@ -37,7 +37,7 @@ To complete this step, you must have a Control workspace, and you’ll need acce
  1. Log in to your DNS service provider (which may be the website you purchased the domain from or that currently hosts the domain, like NameCheap, GoDaddy, DNSMadeEasy, or Amazon Route53. You may need to contact your company’s IT department if your domain is managed internally).
  2. Find the page for DNS records, which might be labeled as DNS Management or Zone File Editor.
  3. -
  4. Add a new TXT record and set the value as 532F6180D8.
  5. +
  6. Add a new TXT record with the value assigned to you in the domain verification settings.
  7. Save your changes.
  8. In Expensify, click the Domain Members tab and click Verify.
@@ -48,4 +48,4 @@ After successful verification, an email will be sent to all members of the Expen To add an additional domain, you’ll have to first add your email address that is connected with your domain as your [primary or secondary email] (https://help.expensify.com/articles/expensify-classic/settings/account-settings/Change-or-add-email-address) (for example, if your domain is yourcompany.com, then you want to add and verify your email address @yourcompany.com as your primary or secondary email address). Then you can complete the steps above to add the domain. - \ No newline at end of file + diff --git a/docs/articles/expensify-classic/settings/account-settings/Add-profile-photo.md b/docs/articles/expensify-classic/settings/Add-profile-photo.md similarity index 100% rename from docs/articles/expensify-classic/settings/account-settings/Add-profile-photo.md rename to docs/articles/expensify-classic/settings/Add-profile-photo.md diff --git a/docs/articles/expensify-classic/settings/account-settings/Change-or-add-email-address.md b/docs/articles/expensify-classic/settings/Change-or-add-email-address.md similarity index 100% rename from docs/articles/expensify-classic/settings/account-settings/Change-or-add-email-address.md rename to docs/articles/expensify-classic/settings/Change-or-add-email-address.md diff --git a/docs/articles/expensify-classic/settings/account-settings/Close-or-reopen-account.md b/docs/articles/expensify-classic/settings/Close-or-reopen-account.md similarity index 100% rename from docs/articles/expensify-classic/settings/account-settings/Close-or-reopen-account.md rename to docs/articles/expensify-classic/settings/Close-or-reopen-account.md diff --git a/docs/articles/expensify-classic/settings/account-settings/Manage-devices.md b/docs/articles/expensify-classic/settings/Manage-devices.md similarity index 100% rename from docs/articles/expensify-classic/settings/account-settings/Manage-devices.md rename to docs/articles/expensify-classic/settings/Manage-devices.md diff --git a/docs/articles/expensify-classic/settings/account-settings/Merge-accounts.md b/docs/articles/expensify-classic/settings/Merge-accounts.md similarity index 100% rename from docs/articles/expensify-classic/settings/account-settings/Merge-accounts.md rename to docs/articles/expensify-classic/settings/Merge-accounts.md diff --git a/docs/articles/expensify-classic/settings/account-settings/Set-Notifications.md b/docs/articles/expensify-classic/settings/Set-Notifications.md similarity index 100% rename from docs/articles/expensify-classic/settings/account-settings/Set-Notifications.md rename to docs/articles/expensify-classic/settings/Set-Notifications.md diff --git a/docs/articles/expensify-classic/settings/account-settings/Set-time-zone.md b/docs/articles/expensify-classic/settings/Set-time-zone.md similarity index 100% rename from docs/articles/expensify-classic/settings/account-settings/Set-time-zone.md rename to docs/articles/expensify-classic/settings/Set-time-zone.md diff --git a/docs/articles/new-expensify/expenses-&-payments/Set-up-your-wallet.md b/docs/articles/new-expensify/expenses-&-payments/Set-up-your-wallet.md index 7f7b6196707d..fbed5048e575 100644 --- a/docs/articles/new-expensify/expenses-&-payments/Set-up-your-wallet.md +++ b/docs/articles/new-expensify/expenses-&-payments/Set-up-your-wallet.md @@ -2,24 +2,21 @@ title: Set up your wallet description: Send and receive payments by adding your payment account --- -
-To send and receive money using Expensify, you’ll first need to set up your Expensify Wallet by adding your payment account. -![The Wallet Tab where you can add a personal bank account]({{site.url}}/assets/images/ExpensifyHelp_R5_Wallet_1.png){:width="100%"} +The Expensify Wallet allows you to receive peer-to-peer payments. To set this up, you’ll first need to connect a personal bank account. -{% include selector.html values="desktop, mobile" %} +![The Wallet Tab where you can add a personal bank account]({{site.url}}/assets/images/ExpensifyHelp_R5_Wallet_1.png){:width="100%"} -{% include option.html value="desktop" %} +**To enable the Expensify Wallet:** 1. Click your profile image or icon in the bottom left menu. 2. Click **Wallet** in the left menu. 3. Click **Enable wallet**. -4. If you haven’t already added your bank account, click **Continue** and follow the prompts to add your bank account details with Plaid. If you have already connected your bank account, you’ll skip to the next step. +4. If you haven’t already added your bank account, click **Continue** and follow the prompts to [connect your personal bank account](https://help.expensify.com/articles/new-expensify/expenses-&-payments/Connect-a-Personal-Bank-Account) via Plaid. If you have already connected your bank account, you’ll skip to the next step. {% include info.html %} Plaid is an encrypted third-party financial data platform that Expensify uses to securely verify your banking information. {% include end-info.html %} -{:start="5"} 5. Enter your personal details (including your name, address, date of birth, phone number, and the last 4 digits of your social security number). 6. Click **Save & continue**. 7. Review the Onfido terms and click **Accept**. @@ -27,28 +24,3 @@ Plaid is an encrypted third-party financial data platform that Expensify uses to 9. Follow the prompts on your mobile device to submit your ID with Onfido. When your ID is uploaded successfully, Onfido closes automatically. You can return to your Expensify Wallet to verify that it is now enabled. Once enabled, you are ready to send and receive payments. -{% include end-option.html %} - -{% include option.html value="mobile" %} -1. Tap your profile image or icon in the bottom menu. -2. Tap **Wallet**. -3. Tap **Enable wallet**. -4. If you haven’t already added your bank account, tap **Continue** and follow the prompts to add your bank account details with Plaid. If you have already connected your bank account, you’ll skip to the next step. - -{% include info.html %} -Plaid is an encrypted third-party financial data platform that Expensify uses to securely verify your banking information. -{% include end-info.html %} - -{:start="5"} -5. Enter your personal details (including your name, address, date of birth, phone number, and the last 4 digits of your social security number). -6. Tap **Save & continue**. -7. Review the Onfido terms and tap **Accept**. -8. Follow the prompts to submit your ID with Onfido. When your ID is uploaded successfully, Onfido closes automatically. -9. Tap **Enable wallet** again to enable payments for the wallet. - -Once enabled, you are ready to send and receive payments. -{% include end-option.html %} - -{% include end-selector.html %} - -
diff --git a/docs/expensify-classic/hubs/settings/account-settings.html b/docs/expensify-classic/hubs/settings/account-settings.html deleted file mode 100644 index e53f92312b7c..000000000000 --- a/docs/expensify-classic/hubs/settings/account-settings.html +++ /dev/null @@ -1,6 +0,0 @@ ---- -layout: default -title: Account Settings ---- - -{% include section.html %} diff --git a/docs/redirects.csv b/docs/redirects.csv index 55cfd267f651..b47d6f2ae25c 100644 --- a/docs/redirects.csv +++ b/docs/redirects.csv @@ -130,7 +130,6 @@ https://help.expensify.com/articles/expensify-classic/reports/Expense-Rules,http https://help.expensify.com/articles/expensify-classic/reports/Currency,https://help.expensify.com/articles/expensify-classic/workspaces/Currency https://help.expensify.com/articles/expensify-classic/reports/The-Expenses-Page,https://help.expensify.com/articles/expensify-classic/expenses/The-Expenses-Page https://help.expensify.com/articles/expensify-classic/reports/Attendee-Tracking,https://help.expensify.com/articles/expensify-classic/expenses/Track-group-expenses -https://help.expensify.com/articles/expensify-classic/account-settings/Close-Account,https://help.expensify.com/articles/expensify-classic/settings/Close-or-reopen-account https://help.expensify.com/articles/expensify-classic/account-settings/Copilot,https://help.expensify.com/expensify-classic/hubs/copilots-and-delegates/ https://help.expensify.com/articles/expensify-classic/account-settings/Notification-Troubleshooting,https://help.expensify.com/articles/expensify-classic/settings/Notification-Troubleshooting https://help.expensify.com/articles/expensify-classic/billing-and-subscriptions/Annual-Subscription,https://help.expensify.com/articles/expensify-classic/expensify-billing/Billing-Overview @@ -199,6 +198,13 @@ https://help.expensify.com/articles/expensify-classic/workspaces/reports/Report- https://help.expensify.com/articles/expensify-classic/workspaces/reports/Scheduled-Submit,https://help.expensify.com/articles/expensify-classic/reports/Automatically-submit-employee-reports https://help.expensify.com/articles/new-expensify/chat/Expensify-Chat-For-Admins,https://help.expensify.com/new-expensify/hubs/chat/ https://help.expensify.com/articles/new-expensify/bank-accounts-and-payments/Connect-a-Bank-Account.html,https://help.expensify.com/articles/new-expensify/expenses/Connect-a-Business-Bank-Account +https://help.expensify.com/articles/expensify-classic/settings/account-settings/Add-profile-photo,https://help.expensify.com/articles/expensify-classic/settings/Add-profile-photo +https://help.expensify.com/articles/expensify-classic/settings/account-settings/Change-or-add-email-address,https://help.expensify.com/articles/expensify-classic/settings/Change-or-add-email-address +https://help.expensify.com/articles/expensify-classic/settings/account-settings/Close-or-reopen-account,https://help.expensify.com/articles/expensify-classic/settings/Close-or-reopen-account +https://help.expensify.com/articles/expensify-classic/settings/account-settings/Manage-devices,https://help.expensify.com/articles/expensify-classic/settings/Manage-devices +https://help.expensify.com/articles/expensify-classic/settings/account-settings/Merge-accounts,https://help.expensify.com/articles/expensify-classic/settings/Merge-accounts +https://help.expensify.com/articles/expensify-classic/settings/account-settings/Set-Notifications,https://help.expensify.com/articles/expensify-classic/settings/Set-Notifications +https://help.expensify.com/articles/expensify-classic/settings/account-settings/Set-time-zone,https://help.expensify.com/articles/expensify-classic/settings/Set-time-zone https://help.expensify.com/articles/expensify-classic/travel/Coming-Soon,https://help.expensify.com/expensify-classic/hubs/travel/ https://help.expensify.com/articles/new-expensify/expenses/Manually-submit-reports-for-approval,https://help.expensify.com/new-expensify/hubs/expenses/ https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/Reimbursements.html,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/payments/Receive-Payments @@ -272,7 +278,6 @@ https://help.expensify.com/articles/expensify-classic/integrations/travel-integr https://help.expensify.com/articles/expensify-classic/integrations/HR-integrations/Workday.html,https://help.expensify.com/articles/expensify-classic/connections/Workday https://help.expensify.com/articles/expensify-classic/integrations/accounting-integrations/Xero.html,https://help.expensify.com/expensify-classic/hubs/connections/xero https://help.expensify.com/articles/expensify-classic/integrations/HR-integrations/Zenefits.html,https://help.expensify.com/articles/expensify-classic/connections/Zenefits -https://help.expensify.com/articles/expensify-classic/settings/Close-or-reopen-account,https://help.expensify.com/articles/expensify-classic/settings/account-settings/Close-or-reopen-account https://help.expensify.com/articles/new-expensify/connections/Set-Up-NetSuite-Connection,https://help.expensify.com/articles/new-expensify/connections/netsuite/Connect-to-NetSuite https://help.expensify.com/articles/new-expensify/connections/Set-Up-NetSuite-Connection.html,https://help.expensify.com/articles/new-expensify/connections/netsuite/Connect-to-NetSuite https://help.expensify.com/articles/new-expensify/connections/Set-up-QuickBooks-Online-connection,https://help.expensify.com/articles/new-expensify/connections/quickbooks-online/Connect-to-QuickBooks-Online @@ -563,9 +568,13 @@ https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/Reimbursing-Reports,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/payments/Reimburse-Reports-Invoices-and-Bills https://help.expensify.com/articles/expensify-classic/connect-credit-cards/Global-Reimbursements,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Enable-Global-Reimbursements https://community.expensify.com/discussion/4641/how-to-add-a-deposit-only-bank-account-both-personal-and-business,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Connect-US-Business-Bank-Account -https://community.expensify.com/discussion/5940/how-to-get-reimbursed-outside-the-us-with-wise-for-non-us-employees,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/Third-Party-Payments +https://community.expensify.com/discussion/5940/how-to-get-reimbursed-outside-the-us-with-wise-for-non-us-employees,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/payments/Get-reimbursed-faster-as-a-non-US-employee https://help.expensify.com/articles/expensify-classic/spending-insights,https://help.expensify.com/articles/expensify-classic/spending-insights/Custom-Templates https://help.expensify.com/articles/expensify-classic/settings/account-settings/Set-notifications,https://help.expensify.com/articles/expensify-classic/settings/account-settings/Set-Notifications https://help.expensify.com/articles/new-expensify/getting-started/Upgrade-to-a-Collect-Plan,https://help.expensify.com/Hidden/Upgrade-to-a-Collect-Plan https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/payments/Reimburse-Reports-Invoices-and-Bills,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/payments/Reimburse-Reports https://help.expensify.com/articles/new-expensify/expenses-&-payments/pay-an-invoice.html,https://help.expensify.com/articles/new-expensify/expenses-&-payments/Pay-an-invoice +https://community.expensify.com/discussion/4707/how-to-set-up-your-mobile-app,https://help.expensify.com/articles/expensify-classic/getting-started/Join-your-company's-workspace#download-the-mobile-app +https://community.expensify.com//discussion/6927/deep-dive-how-can-i-estimate-the-savings-applied-to-my-bill,https://help.expensify.com/articles/expensify-classic/expensify-billing/Billing-Overview#savings-calculator +https://community.expensify.com/discussion/5179/faq-what-does-a-policy-for-which-you-are-an-admin-has-out-of-date-billing-information-mean,https://help.expensify.com/articles/expensify-classic/expensify-billing/Out-of-date-Billing +https://community.expensify.com/discussion/6179/setting-up-a-receipt-or-travel-integration-with-expensify,https://help.expensify.com/articles/expensify-classic/connections/Additional-Travel-Integrations \ No newline at end of file diff --git a/ios/NewExpensify.xcodeproj/project.pbxproj b/ios/NewExpensify.xcodeproj/project.pbxproj index 19e80e80c59e..768062717d4b 100644 --- a/ios/NewExpensify.xcodeproj/project.pbxproj +++ b/ios/NewExpensify.xcodeproj/project.pbxproj @@ -16,6 +16,8 @@ 0CDA8E35287DD650004ECBEC /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0CDA8E33287DD650004ECBEC /* AppDelegate.mm */; }; 0CDA8E37287DD6A0004ECBEC /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0CDA8E36287DD6A0004ECBEC /* Images.xcassets */; }; 0CDA8E38287DD6A0004ECBEC /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0CDA8E36287DD6A0004ECBEC /* Images.xcassets */; }; + 0DFC45942C884E0A00B56C91 /* RCTShortcutManagerModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DFC45932C884E0A00B56C91 /* RCTShortcutManagerModule.m */; }; + 0DFC45952C884E0A00B56C91 /* RCTShortcutManagerModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DFC45932C884E0A00B56C91 /* RCTShortcutManagerModule.m */; }; 0F5BE0CE252686330097D869 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0F5BE0CD252686320097D869 /* GoogleService-Info.plist */; }; 0F5E5350263B73FD004CA14F /* EnvironmentChecker.m in Sources */ = {isa = PBXBuildFile; fileRef = 0F5E534F263B73FD004CA14F /* EnvironmentChecker.m */; }; 0F5E5351263B73FD004CA14F /* EnvironmentChecker.m in Sources */ = {isa = PBXBuildFile; fileRef = 0F5E534F263B73FD004CA14F /* EnvironmentChecker.m */; }; @@ -89,7 +91,9 @@ 083353EA2B5AB22900C603C0 /* success.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = success.mp3; path = ../assets/sounds/success.mp3; sourceTree = ""; }; 0CDA8E33287DD650004ECBEC /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = NewExpensify/AppDelegate.mm; sourceTree = ""; }; 0CDA8E36287DD6A0004ECBEC /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = NewExpensify/Images.xcassets; sourceTree = ""; }; - 0D3F9E814828D91464DF9D35 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = NewExpensify/PrivacyInfo.xcprivacy; sourceTree = ""; }; + 0D3F9E814828D91464DF9D35 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = NewExpensify/PrivacyInfo.xcprivacy; sourceTree = ""; }; + 0DFC45922C884D7900B56C91 /* RCTShortcutManagerModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTShortcutManagerModule.h; sourceTree = ""; }; + 0DFC45932C884E0A00B56C91 /* RCTShortcutManagerModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTShortcutManagerModule.m; sourceTree = ""; }; 0F5BE0CD252686320097D869 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 0F5E534E263B73D5004CA14F /* EnvironmentChecker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EnvironmentChecker.h; sourceTree = ""; }; 0F5E534F263B73FD004CA14F /* EnvironmentChecker.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EnvironmentChecker.m; sourceTree = ""; }; @@ -279,6 +283,8 @@ 83CBB9F61A601CBA00E9B192 = { isa = PBXGroup; children = ( + 0DFC45922C884D7900B56C91 /* RCTShortcutManagerModule.h */, + 0DFC45932C884E0A00B56C91 /* RCTShortcutManagerModule.m */, 499B0DA92BE2A1C000CABFB0 /* PrivacyInfo.xcprivacy */, 374FB8D528A133A7000D84EF /* OriginImageRequestHandler.h */, 374FB8D628A133FE000D84EF /* OriginImageRequestHandler.mm */, @@ -888,6 +894,7 @@ buildActionMask = 2147483647; files = ( 0F5E5351263B73FD004CA14F /* EnvironmentChecker.m in Sources */, + 0DFC45952C884E0A00B56C91 /* RCTShortcutManagerModule.m in Sources */, 0CDA8E35287DD650004ECBEC /* AppDelegate.mm in Sources */, 7041848626A8E47D00E09F4D /* RCTStartupTimer.m in Sources */, 7F5E81F06BCCF61AD02CEA06 /* ExpoModulesProvider.swift in Sources */, @@ -899,6 +906,7 @@ buildActionMask = 2147483647; files = ( 18D050E0262400AF000D658B /* BridgingFile.swift in Sources */, + 0DFC45942C884E0A00B56C91 /* RCTShortcutManagerModule.m in Sources */, 0F5E5350263B73FD004CA14F /* EnvironmentChecker.m in Sources */, 374FB8D728A133FE000D84EF /* OriginImageRequestHandler.mm in Sources */, 7041848526A8E47D00E09F4D /* RCTStartupTimer.m in Sources */, diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 51e5a5c0d512..717ffc789054 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 9.0.34 + 9.0.36 CFBundleSignature ???? CFBundleURLTypes @@ -40,7 +40,7 @@ CFBundleVersion - 9.0.34.2 + 9.0.36.1 FullStory OrgId diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 3d812816f637..ee36b22be568 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 9.0.34 + 9.0.36 CFBundleSignature ???? CFBundleVersion - 9.0.34.2 + 9.0.36.1 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 34a3a269f0ff..39dbe2194b38 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -11,9 +11,9 @@ CFBundleName $(PRODUCT_NAME) CFBundleShortVersionString - 9.0.34 + 9.0.36 CFBundleVersion - 9.0.34.2 + 9.0.36.1 NSExtension NSExtensionPointIdentifier diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 945f47b718bf..a8d151d3811d 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -27,8 +27,6 @@ PODS: - AppAuth/ExternalUserAgent (1.7.5): - AppAuth/Core - boost (1.84.0) - - BVLinearGradient (2.8.1): - - React-Core - DoubleConversion (1.1.6) - EXAV (14.0.7): - ExpoModulesCore @@ -1689,7 +1687,7 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - react-native-keyboard-controller (1.12.2): + - react-native-keyboard-controller (1.12.7): - DoubleConversion - glog - hermes-engine @@ -1776,7 +1774,7 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - react-native-pdf (6.7.3): + - react-native-pdf (6.7.5): - DoubleConversion - glog - hermes-engine @@ -2362,7 +2360,7 @@ PODS: - RNGoogleSignin (10.0.1): - GoogleSignIn (~> 7.0) - React-Core - - RNLiveMarkdown (0.1.120): + - RNLiveMarkdown (0.1.143): - DoubleConversion - glog - hermes-engine @@ -2382,9 +2380,9 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - RNLiveMarkdown/common (= 0.1.120) + - RNLiveMarkdown/common (= 0.1.143) - Yoga - - RNLiveMarkdown/common (0.1.120): + - RNLiveMarkdown/common (0.1.143): - DoubleConversion - glog - hermes-engine @@ -2453,7 +2451,7 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - RNReactNativeHapticFeedback (2.2.0): + - RNReactNativeHapticFeedback (2.3.1): - DoubleConversion - glog - hermes-engine @@ -2584,7 +2582,7 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - RNShare (10.0.2): + - RNShare (11.0.2): - DoubleConversion - glog - hermes-engine @@ -2692,7 +2690,6 @@ PODS: 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`) - EXAV (from `../node_modules/expo-av/ios`) - EXImageLoader (from `../node_modules/expo-image-loader/ios`) @@ -2856,8 +2853,6 @@ SPEC REPOS: EXTERNAL SOURCES: boost: :podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec" - BVLinearGradient: - :path: "../node_modules/react-native-linear-gradient" DoubleConversion: :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" EXAV: @@ -3102,7 +3097,6 @@ SPEC CHECKSUMS: AirshipServiceExtension: 9c73369f426396d9fb9ff222d86d842fac76ba46 AppAuth: 501c04eda8a8d11f179dbe8637b7a91bb7e5d2fa boost: 26992d1adf73c1c7676360643e687aee6dda994b - BVLinearGradient: 421743791a59d259aec53f4c58793aad031da2ca DoubleConversion: 76ab83afb40bddeeee456813d9c04f67f78771b5 EXAV: afa491e598334bbbb92a92a2f4dd33d7149ad37f EXImageLoader: ab589d67d6c5f2c33572afea9917304418566334 @@ -3184,11 +3178,11 @@ SPEC CHECKSUMS: react-native-geolocation: b9bd12beaf0ebca61a01514517ca8455bd26fa06 react-native-image-picker: f8a13ff106bcc7eb00c71ce11fdc36aac2a44440 react-native-key-command: aae312752fcdfaa2240be9a015fc41ce54087546 - react-native-keyboard-controller: 5075321af7b1c834cfb9582230659d032c963278 + react-native-keyboard-controller: b9b2ba987e3c6f4b6534740e88d11dccc34f69dc react-native-launch-arguments: 5f41e0abf88a15e3c5309b8875d6fd5ac43df49d react-native-netinfo: fb5112b1fa754975485884ae85a3fb6a684f49d5 react-native-pager-view: 94195f1bf32e7f78359fa20057c97e632364a08b - react-native-pdf: dd6ae39a93607a80919bef9f3499e840c693989d + react-native-pdf: 2e2591ebd39422163850403b1c0cd7d6b351e168 react-native-performance: 3c608307be10964f8a97d3af462f37125b6d8fa5 react-native-plaid-link-sdk: f91a22b45b7c3d4cd6c47273200dc57df35068b0 react-native-quick-sqlite: 7c793c9f5834e756b336257a8d8b8239b7ceb451 @@ -3235,14 +3229,14 @@ SPEC CHECKSUMS: RNFS: 4ac0f0ea233904cb798630b3c077808c06931688 RNGestureHandler: 8781e2529230a1bc3ea8d75e5c3cd071b6c6aed7 RNGoogleSignin: ccaa4a81582cf713eea562c5dd9dc1961a715fd0 - RNLiveMarkdown: cfc927fc0b1182e364237c72692e079107c6f5f1 + RNLiveMarkdown: e44918843c2638692348f39eafc275698baf0444 RNLocalize: d4b8af4e442d4bcca54e68fc687a2129b4d71a81 rnmapbox-maps: 460d6ff97ae49c7d5708c3212c6521697c36a0c4 RNPermissions: 0b1429b55af59d1d08b75a8be2459f65a8ac3f28 - RNReactNativeHapticFeedback: a15b431d2903bc2eb3474ff8d9a05d3e67a70199 + RNReactNativeHapticFeedback: 31833c3ef341d716dbbd9d64e940f0c230db46f6 RNReanimated: 76901886830e1032f16bbf820153f7dc3f02d51d RNScreens: de6e57426ba0e6cbc3fb5b4f496e7f08cb2773c2 - RNShare: a3c2fbbca5682530b65ff405b34c91dad1e22442 + RNShare: bd4fe9b95d1ee89a200778cc0753ebe650154bb0 RNSound: 6c156f925295bdc83e8e422e7d8b38d33bc71852 RNSVG: 1079f96b39a35753d481a20e30603fd6fc4f6fa9 SDWebImage: 066c47b573f408f18caa467d71deace7c0f8280d diff --git a/ios/RCTShortcutManagerModule.h b/ios/RCTShortcutManagerModule.h new file mode 100644 index 000000000000..5d596d5e7a5e --- /dev/null +++ b/ios/RCTShortcutManagerModule.h @@ -0,0 +1,4 @@ +// RCTShortcutManagerModule.h +#import +@interface RCTShortcutManagerModule : NSObject +@end diff --git a/ios/RCTShortcutManagerModule.m b/ios/RCTShortcutManagerModule.m new file mode 100644 index 000000000000..bab19019a967 --- /dev/null +++ b/ios/RCTShortcutManagerModule.m @@ -0,0 +1,11 @@ +// RCTCalendarModule.m +// iOS doesn't have dynamic shortcuts like Android, so this module contains noop functions to prevent iOS from crashing +#import "RCTShortcutManagerModule.h" + +@implementation RCTShortcutManagerModule + +RCT_EXPORT_METHOD(removeAllDynamicShortcuts){} + +RCT_EXPORT_MODULE(ShortcutManager); + +@end diff --git a/metro.config.js b/metro.config.js index 0ad3bafc011e..c6e4ba6bb4ec 100644 --- a/metro.config.js +++ b/metro.config.js @@ -1,10 +1,13 @@ -const {getDefaultConfig} = require('expo/metro-config'); +const {getDefaultConfig: getExpoDefaultConfig} = require('expo/metro-config'); +const {getDefaultConfig: getReactNativeDefaultConfig} = require('@react-native/metro-config'); + const {mergeConfig} = require('@react-native/metro-config'); const defaultAssetExts = require('metro-config/src/defaults/defaults').assetExts; const defaultSourceExts = require('metro-config/src/defaults/defaults').sourceExts; require('dotenv').config(); -const defaultConfig = getDefaultConfig(__dirname); +const defaultConfig = getReactNativeDefaultConfig(__dirname); +const expoConfig = getExpoDefaultConfig(__dirname); const isE2ETesting = process.env.E2E_TESTING === 'true'; const e2eSourceExts = ['e2e.js', 'e2e.ts', 'e2e.tsx']; @@ -23,4 +26,4 @@ const config = { }, }; -module.exports = mergeConfig(defaultConfig, config); +module.exports = mergeConfig(defaultConfig, expoConfig, config); diff --git a/package-lock.json b/package-lock.json index 18bac528ad99..85c6fc1d0a45 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,33 +1,27 @@ { "name": "new.expensify", - "version": "9.0.34-2", + "version": "9.0.36-1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "9.0.34-2", + "version": "9.0.36-1", "hasInstallScript": true, "license": "MIT", "dependencies": { - "@babel/plugin-proposal-private-methods": "^7.18.6", - "@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@dotlottie/react-player": "^1.6.3", - "@expensify/react-native-live-markdown": "0.1.120", + "@expensify/react-native-live-markdown": "0.1.143", "@expo/metro-runtime": "~3.2.3", "@formatjs/intl-datetimeformat": "^6.12.5", "@formatjs/intl-listformat": "^7.5.7", "@formatjs/intl-locale": "^4.0.0", "@formatjs/intl-numberformat": "^8.10.3", "@formatjs/intl-pluralrules": "^5.2.14", - "@fullstory/babel-plugin-annotate-react": "github:fullstorydev/fullstory-babel-plugin-annotate-react#ryanwang/react-native-web-demo", - "@fullstory/babel-plugin-react-native": "^1.2.1", "@fullstory/browser": "^2.0.3", "@fullstory/react-native": "^1.4.2", "@gorhom/portal": "^1.0.14", "@invertase/react-native-apple-authentication": "^2.2.2", - "@kie/act-js": "^2.6.2", - "@kie/mock-github": "2.0.1", "@onfido/react-native-sdk": "10.6.0", "@react-native-camera-roll/camera-roll": "7.4.0", "@react-native-clipboard/clipboard": "^1.13.2", @@ -45,7 +39,6 @@ "@react-ng/bounds-observer": "^0.2.1", "@rnmapbox/maps": "10.1.30", "@shopify/flash-list": "1.7.1", - "@types/mime-db": "^1.43.5", "@ua/react-native-airship": "19.2.1", "@vue/preload-webpack-plugin": "^2.0.0", "awesome-phonenumber": "^5.4.0", @@ -94,18 +87,17 @@ "react-native-fs": "^2.20.0", "react-native-gesture-handler": "2.18.0", "react-native-google-places-autocomplete": "2.5.6", - "react-native-haptic-feedback": "^2.2.0", + "react-native-haptic-feedback": "^2.3.1", "react-native-image-picker": "^7.0.3", "react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#cb392140db4953a283590d7cf93b4d0461baa2a9", "react-native-key-command": "^1.0.8", - "react-native-keyboard-controller": "^1.12.2", + "react-native-keyboard-controller": "1.12.7", "react-native-launch-arguments": "^4.0.2", - "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "2.0.66", + "react-native-onyx": "2.0.68", "react-native-pager-view": "6.4.1", - "react-native-pdf": "6.7.3", + "react-native-pdf": "6.7.5", "react-native-performance": "^5.1.0", "react-native-permissions": "^3.10.0", "react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#da50d2c5c54e268499047f9cc98b8df4196c1ddf", @@ -117,7 +109,7 @@ "react-native-render-html": "6.3.1", "react-native-safe-area-context": "4.10.9", "react-native-screens": "3.34.0", - "react-native-share": "^10.0.2", + "react-native-share": "11.0.2", "react-native-sound": "^0.11.2", "react-native-svg": "15.6.0", "react-native-tab-view": "^3.5.2", @@ -125,14 +117,12 @@ "react-native-view-shot": "3.8.0", "react-native-vision-camera": "4.0.0-beta.13", "react-native-web": "^0.19.12", - "react-native-web-linear-gradient": "^1.1.2", "react-native-web-sound": "^0.1.3", "react-native-webview": "13.8.6", "react-pdf": "^7.7.3", "react-plaid-link": "3.3.2", "react-web-config": "^1.0.0", "react-webcam": "^7.1.1", - "react-window": "^1.8.9", "semver": "^7.5.2", "xlsx": "file:vendor/xlsx-0.20.3.tgz" }, @@ -143,6 +133,8 @@ "@babel/parser": "^7.22.16", "@babel/plugin-proposal-class-properties": "^7.12.1", "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@babel/preset-env": "^7.20.0", "@babel/preset-flow": "^7.12.13", "@babel/preset-react": "^7.10.4", @@ -153,6 +145,7 @@ "@callstack/reassure-compare": "^1.0.0-rc.4", "@dword-design/eslint-plugin-import-alias": "^5.0.0", "@electron/notarize": "^2.1.0", + "@fullstory/babel-plugin-annotate-react": "^2.3.0", "@jest/globals": "^29.5.0", "@ngneat/falso": "^7.1.1", "@octokit/core": "4.0.4", @@ -185,6 +178,7 @@ "@types/js-yaml": "^4.0.5", "@types/lodash": "^4.14.195", "@types/mapbox-gl": "^2.7.13", + "@types/mime-db": "^1.43.5", "@types/node": "^20.11.5", "@types/pusher-js": "^5.1.0", "@types/react": "^18.2.6", @@ -233,7 +227,6 @@ "eslint-plugin-you-dont-need-lodash-underscore": "^6.14.0", "html-webpack-plugin": "^5.5.0", "http-server": "^14.1.1", - "husky": "^9.1.5", "jest": "29.4.1", "jest-circus": "29.4.1", "jest-cli": "29.4.1", @@ -269,8 +262,7 @@ "webpack-bundle-analyzer": "^4.5.0", "webpack-cli": "^5.0.4", "webpack-dev-server": "^5.0.4", - "webpack-merge": "^5.8.0", - "yaml": "^2.2.1" + "webpack-merge": "^5.8.0" }, "engines": { "node": "20.15.1", @@ -1349,7 +1341,10 @@ }, "node_modules/@babel/plugin-proposal-private-methods": { "version": "7.18.6", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead.", + "dev": true, "dependencies": { "@babel/helper-create-class-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -1363,7 +1358,10 @@ }, "node_modules/@babel/plugin-proposal-private-property-in-object": { "version": "7.21.11", - "license": "MIT", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz", + "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-property-in-object instead.", + "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", "@babel/helper-create-class-features-plugin": "^7.21.0", @@ -3571,9 +3569,9 @@ } }, "node_modules/@expensify/react-native-live-markdown": { - "version": "0.1.120", - "resolved": "https://registry.npmjs.org/@expensify/react-native-live-markdown/-/react-native-live-markdown-0.1.120.tgz", - "integrity": "sha512-MQ8/gPb2u8U1HPClwKhrf2sqjCpi56g5aEhonYOejMPd7kUKpV0nlccSJgy5UEwJFhtxL+cl7SgnXq8xJNwxng==", + "version": "0.1.143", + "resolved": "https://registry.npmjs.org/@expensify/react-native-live-markdown/-/react-native-live-markdown-0.1.143.tgz", + "integrity": "sha512-hZXYjKyTl/b2p7Ig9qhoB7cfVtTTcoE2cWvea8NJT3f5ZYckdyHDAgHI4pg0S0N68jP205Sk5pzqlltZUpZk5w==", "workspaces": [ "parser", "example", @@ -5565,11 +5563,13 @@ }, "node_modules/@fullstory/babel-plugin-annotate-react": { "version": "2.3.0", - "resolved": "git+ssh://git@github.com/fullstorydev/fullstory-babel-plugin-annotate-react.git#25c26dadb644d5355e381a4ea4ca1cd05af4a8f6" + "resolved": "https://registry.npmjs.org/@fullstory/babel-plugin-annotate-react/-/babel-plugin-annotate-react-2.3.0.tgz", + "integrity": "sha512-gYLUL6Tu0exbvTIhK9nSCaztmqBlQAm07Fvtl/nKTc+lxwFkcX9vR8RrdTbyjJZKbPaA5EMlExQ6GeLCXkfm5g==" }, "node_modules/@fullstory/babel-plugin-react-native": { - "version": "1.2.1", - "license": "MIT", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@fullstory/babel-plugin-react-native/-/babel-plugin-react-native-1.3.0.tgz", + "integrity": "sha512-JSWV/fn5sEAUHhXD8CvyVTHAtttNjokLHguZ7pxh2EbG1TOg5yBCvXnF+yQ6heS5PKJen7TMS2mdBaXtnYEPIQ==", "dependencies": { "@babel/parser": "^7.0.0", "@babel/types": "^7.0.0" @@ -6516,59 +6516,9 @@ "react-native": "*" } }, - "node_modules/@kie/act-js": { - "version": "2.6.2", - "hasInstallScript": true, - "license": "SEE LICENSE IN LICENSE", - "dependencies": { - "@kie/mock-github": "^2.0.0", - "adm-zip": "^0.5.10", - "ajv": "^8.12.0", - "bin-links": "^4.0.1", - "express": "^4.18.1", - "follow-redirects": "^1.15.2", - "tar": "^6.1.13", - "yaml": "^2.1.3" - }, - "bin": { - "act-js": "bin/act" - } - }, - "node_modules/@kie/mock-github": { - "version": "2.0.1", - "license": "SEE LICENSE IN LICENSE", - "dependencies": { - "@octokit/openapi-types-ghec": "^18.0.0", - "ajv": "^8.11.0", - "express": "^4.18.1", - "fast-glob": "^3.2.12", - "fs-extra": "^10.1.0", - "nock": "^13.2.7", - "simple-git": "^3.8.0", - "totalist": "^3.0.0" - } - }, - "node_modules/@kie/mock-github/node_modules/fs-extra": { - "version": "10.1.0", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@kie/mock-github/node_modules/totalist": { - "version": "3.0.1", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/@kwsites/file-exists": { "version": "1.1.1", + "dev": true, "license": "MIT", "dependencies": { "debug": "^4.1.1" @@ -6576,6 +6526,7 @@ }, "node_modules/@kwsites/promise-deferred": { "version": "1.1.1", + "dev": true, "license": "MIT" }, "node_modules/@leichtgewicht/ip-codec": { @@ -6984,10 +6935,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@octokit/openapi-types-ghec": { - "version": "18.1.1", - "license": "MIT" - }, "node_modules/@octokit/plugin-paginate-rest": { "version": "3.1.0", "dev": true, @@ -15741,7 +15688,8 @@ "node_modules/@types/mime-db": { "version": "1.43.5", "resolved": "https://registry.npmjs.org/@types/mime-db/-/mime-db-1.43.5.tgz", - "integrity": "sha512-/bfTiIUTNPUBnwnYvUxXAre5MhD88jgagLEQiQtIASjU+bwxd8kS/ASDA4a8ufd8m0Lheu6eeMJHEUpLHoJ28A==" + "integrity": "sha512-/bfTiIUTNPUBnwnYvUxXAre5MhD88jgagLEQiQtIASjU+bwxd8kS/ASDA4a8ufd8m0Lheu6eeMJHEUpLHoJ28A==", + "dev": true }, "node_modules/@types/minimatch": { "version": "3.0.5", @@ -17013,13 +16961,6 @@ "node": ">=0.4.0" } }, - "node_modules/adm-zip": { - "version": "0.5.10", - "license": "MIT", - "engines": { - "node": ">=6.0" - } - }, "node_modules/agent-base": { "version": "6.0.2", "license": "MIT", @@ -17569,6 +17510,7 @@ }, "node_modules/array-flatten": { "version": "1.1.1", + "dev": true, "license": "MIT" }, "node_modules/array-includes": { @@ -19114,40 +19056,6 @@ "node": "*" } }, - "node_modules/bin-links": { - "version": "4.0.2", - "license": "ISC", - "dependencies": { - "cmd-shim": "^6.0.0", - "npm-normalize-package-bin": "^3.0.0", - "read-cmd-shim": "^4.0.0", - "write-file-atomic": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/bin-links/node_modules/signal-exit": { - "version": "4.1.0", - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/bin-links/node_modules/write-file-atomic": { - "version": "5.0.1", - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/binary-extensions": { "version": "2.2.0", "devOptional": true, @@ -19206,6 +19114,7 @@ "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dev": true, "license": "MIT", "dependencies": { "bytes": "3.1.2", @@ -19230,6 +19139,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -19239,6 +19149,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -19248,6 +19159,7 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" @@ -19260,6 +19172,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, "license": "MIT" }, "node_modules/bonjour-service": { @@ -20404,13 +20317,6 @@ "node": ">=6" } }, - "node_modules/cmd-shim": { - "version": "6.0.1", - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/co": { "version": "4.6.0", "license": "MIT", @@ -20919,6 +20825,7 @@ }, "node_modules/content-disposition": { "version": "0.5.4", + "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" @@ -20929,6 +20836,7 @@ }, "node_modules/content-disposition/node_modules/safe-buffer": { "version": "5.2.1", + "dev": true, "funding": [ { "type": "github", @@ -20949,6 +20857,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -20971,6 +20880,7 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -20978,6 +20888,7 @@ }, "node_modules/cookie-signature": { "version": "1.0.6", + "dev": true, "license": "MIT" }, "node_modules/copy-descriptor": { @@ -25014,6 +24925,7 @@ "version": "4.20.0", "resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz", "integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==", + "dev": true, "license": "MIT", "dependencies": { "accepts": "~1.3.8", @@ -25054,6 +24966,7 @@ }, "node_modules/express/node_modules/debug": { "version": "2.6.9", + "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -25063,6 +24976,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -25072,6 +24986,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, "license": "MIT", "bin": { "mime": "cli.js" @@ -25082,12 +24997,14 @@ }, "node_modules/express/node_modules/ms": { "version": "2.0.0", + "dev": true, "license": "MIT" }, "node_modules/express/node_modules/qs": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.4" @@ -25101,6 +25018,7 @@ }, "node_modules/express/node_modules/safe-buffer": { "version": "5.2.1", + "dev": true, "funding": [ { "type": "github", @@ -25121,6 +25039,7 @@ "version": "0.19.0", "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", @@ -25145,6 +25064,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -25154,6 +25074,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, "license": "MIT" }, "node_modules/extend-shallow": { @@ -25493,6 +25414,7 @@ }, "node_modules/finalhandler": { "version": "1.2.0", + "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", @@ -25509,6 +25431,7 @@ }, "node_modules/finalhandler/node_modules/debug": { "version": "2.6.9", + "dev": true, "license": "MIT", "dependencies": { "ms": "2.0.0" @@ -25516,6 +25439,7 @@ }, "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", + "dev": true, "license": "MIT" }, "node_modules/find-babel-config": { @@ -25682,6 +25606,7 @@ }, "node_modules/follow-redirects": { "version": "1.15.5", + "dev": true, "funding": [ { "type": "individual", @@ -25896,6 +25821,7 @@ }, "node_modules/forwarded": { "version": "0.2.0", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -27179,21 +27105,6 @@ "ms": "^2.0.0" } }, - "node_modules/husky": { - "version": "9.1.5", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.5.tgz", - "integrity": "sha512-rowAVRUBfI0b4+niA4SJMhfQwc107VLkBUgEYYAOQAbqDCnra1nYh83hF/MDmhYs9t9n1E3DuKOrs2LYNC+0Ag==", - "dev": true, - "bin": { - "husky": "bin.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/typicode" - } - }, "node_modules/hyperdyperid": { "version": "1.2.0", "dev": true, @@ -30701,6 +30612,7 @@ }, "node_modules/json-stringify-safe": { "version": "5.0.1", + "dev": true, "license": "ISC" }, "node_modules/json5": { @@ -31920,6 +31832,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -32021,6 +31934,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -32049,6 +31963,7 @@ }, "node_modules/methods": { "version": "1.1.2", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -32937,19 +32852,6 @@ "node": ">=12.0.0" } }, - "node_modules/nock": { - "version": "13.3.3", - "license": "MIT", - "dependencies": { - "debug": "^4.1.0", - "json-stringify-safe": "^5.0.1", - "lodash": "^4.17.21", - "propagate": "^2.0.0" - }, - "engines": { - "node": ">= 10.13" - } - }, "node_modules/node-abi": { "version": "3.65.0", "dev": true, @@ -33254,13 +33156,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npm-normalize-package-bin": { - "version": "3.0.1", - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/npm-package-arg": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-7.0.0.tgz", @@ -34401,6 +34296,7 @@ "version": "0.1.10", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "dev": true, "license": "MIT" }, "node_modules/path-type": { @@ -34934,19 +34830,13 @@ "version": "16.13.1", "license": "MIT" }, - "node_modules/propagate": { - "version": "2.0.1", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, "node_modules/protocol-buffers-schema": { "version": "3.6.0", "license": "MIT" }, "node_modules/proxy-addr": { "version": "2.0.7", + "dev": true, "license": "MIT", "dependencies": { "forwarded": "0.2.0", @@ -35189,6 +35079,7 @@ "version": "6.13.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.6" @@ -35325,6 +35216,7 @@ "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==", + "dev": true, "license": "MIT", "dependencies": { "bytes": "3.1.2", @@ -35340,6 +35232,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8" @@ -35349,6 +35242,7 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" @@ -35916,8 +35810,12 @@ } }, "node_modules/react-native-haptic-feedback": { - "version": "2.2.0", - "license": "MIT", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/react-native-haptic-feedback/-/react-native-haptic-feedback-2.3.1.tgz", + "integrity": "sha512-dPfjV4iVHfhVyfG+nRd88ygjahbdup7KFZDM5L2aNIAzqbNtKxHZn5O1pHegwSj1t15VJliu0GyTX7XpBDeXUw==", + "workspaces": [ + "example" + ], "peerDependencies": { "react-native": ">=0.60.0" } @@ -35954,13 +35852,13 @@ "license": "MIT" }, "node_modules/react-native-keyboard-controller": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/react-native-keyboard-controller/-/react-native-keyboard-controller-1.12.2.tgz", - "integrity": "sha512-10Sy0+neSHGJxOmOxrUJR8TQznnrQ+jTFQtM1PP6YnblNQeAw1eOa+lO6YLGenRr5WuNSMZbks/3Ay0e2yMKLw==", + "version": "1.12.7", + "resolved": "https://registry.npmjs.org/react-native-keyboard-controller/-/react-native-keyboard-controller-1.12.7.tgz", + "integrity": "sha512-eccg0JtZk5n/up3I7pEg606Bo9eLsgVGtTPnmdv507AJg5UeAAMEhx93P7YXDZmwJ+38oFn3DbL7a0eIUE3Lxw==", "peerDependencies": { "react": "*", "react-native": "*", - "react-native-reanimated": ">=2.3.0" + "react-native-reanimated": ">=2.11.0" } }, "node_modules/react-native-launch-arguments": { @@ -35971,14 +35869,6 @@ "react-native": ">=0.60.0-rc.0 <1.0.x" } }, - "node_modules/react-native-linear-gradient": { - "version": "2.8.1", - "license": "MIT", - "peerDependencies": { - "react": "*", - "react-native": "*" - } - }, "node_modules/react-native-localize": { "version": "2.2.6", "license": "MIT", @@ -36760,9 +36650,9 @@ } }, "node_modules/react-native-onyx": { - "version": "2.0.66", - "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-2.0.66.tgz", - "integrity": "sha512-Ns9WzcAjarAUl9g/bftf2EUJYdgcb6BAraxwqBWVeGWk3dGBR1hVEvZ7p/3rpKjidJQqiM3LWBaM6DkNHoYd1g==", + "version": "2.0.68", + "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-2.0.68.tgz", + "integrity": "sha512-KzcG8r6oIHRZhtiGu2XtHwYLm6eTp74r4NyhIawinfJEgcd1YMC6KdrVMqd1J7zFLTuBXPhtjiugTbUhXraFag==", "dependencies": { "ascii-table": "0.0.9", "fast-equals": "^4.0.3", @@ -36805,8 +36695,9 @@ } }, "node_modules/react-native-pdf": { - "version": "6.7.3", - "license": "MIT", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/react-native-pdf/-/react-native-pdf-6.7.5.tgz", + "integrity": "sha512-d1S76p2Vwax2iG+kTnjINiUMvpjtJJvtMiYwHRbgGczT8GJjtXH49YCWOd+HfnUAU29cB+knzsKGYoZBMQM8Ow==", "dependencies": { "crypto-js": "4.2.0", "deprecated-react-native-prop-types": "^2.3.0" @@ -37002,8 +36893,9 @@ } }, "node_modules/react-native-share": { - "version": "10.0.2", - "license": "MIT", + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-11.0.2.tgz", + "integrity": "sha512-7W7sb9qd8RjVEIMhbYc3MU//qGUNxf1XAqd3SlO/ivz89ed1jP1yUwYOcUK2Kf1NDY/kwWbPCkEKa6ZGVlcsOQ==", "engines": { "node": ">=16" } @@ -37094,13 +36986,6 @@ "react-dom": "^18.0.0" } }, - "node_modules/react-native-web-linear-gradient": { - "version": "1.1.2", - "license": "MIT", - "peerDependencies": { - "react-native-web": "*" - } - }, "node_modules/react-native-web-sound": { "version": "0.1.3", "license": "MIT", @@ -38672,13 +38557,6 @@ "read-binary-file-arch": "cli.js" } }, - "node_modules/read-cmd-shim": { - "version": "4.0.0", - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/read-config-file": { "version": "6.4.0", "dev": true, @@ -39942,6 +39820,7 @@ }, "node_modules/simple-git": { "version": "3.24.0", + "dev": true, "license": "MIT", "dependencies": { "@kwsites/file-exists": "^1.1.1", @@ -42070,6 +41949,7 @@ "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, "license": "MIT", "dependencies": { "media-typer": "0.3.0", diff --git a/package.json b/package.json index 9673b5136c4a..8c0da62cc548 100644 --- a/package.json +++ b/package.json @@ -1,35 +1,35 @@ { "name": "new.expensify", - "version": "9.0.34-2", + "version": "9.0.36-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.", "license": "MIT", "private": true, "scripts": { - "configure-mapbox": "scripts/setup-mapbox-sdk-walkthrough.sh", - "setupNewDotWebForEmulators": "scripts/setup-newdot-web-emulators.sh", - "startAndroidEmulator": "scripts/start-android.sh", - "postinstall": "scripts/postInstall.sh", + "configure-mapbox": "./scripts/setup-mapbox-sdk-walkthrough.sh", + "setupNewDotWebForEmulators": "./scripts/setup-newdot-web-emulators.sh", + "startAndroidEmulator": "./scripts/start-android.sh", + "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 --active-arch-only", - "ios": "scripts/set-pusher-suffix.sh && npx react-native run-ios --list-devices --mode=\"DebugDevelopment\" --scheme=\"New Expensify Dev\"", - "pod-install": "scripts/pod-install.sh", + "android": "./scripts/set-pusher-suffix.sh && npx react-native run-android --mode=developmentDebug --appId=com.expensify.chat.dev --active-arch-only", + "ios": "./scripts/set-pusher-suffix.sh && npx react-native run-ios --list-devices --mode=\"DebugDevelopment\" --scheme=\"New Expensify Dev\"", + "pod-install": "./scripts/pod-install.sh", "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": "./scripts/set-pusher-suffix.sh && concurrently npm:web-proxy npm:web-server", "web-proxy": "ts-node web/proxy.ts", "web-server": "webpack-dev-server --open --config config/webpack/webpack.dev.ts", - "build": "webpack --config config/webpack/webpack.common.ts --env file=.env.production && ts-node scripts/combine-web-sourcemaps.ts", - "build-staging": "webpack --config config/webpack/webpack.common.ts --env file=.env.staging && ts-node scripts/combine-web-sourcemaps.ts", - "build-adhoc": "webpack --config config/webpack/webpack.common.ts --env file=.env.adhoc && ts-node scripts/combine-web-sourcemaps.ts", - "desktop": "scripts/set-pusher-suffix.sh && ts-node desktop/start.ts", - "desktop-build": "scripts/build-desktop.sh production", - "desktop-build-staging": "scripts/build-desktop.sh staging", + "build": "webpack --config config/webpack/webpack.common.ts --env file=.env.production && ts-node ./scripts/combine-web-sourcemaps.ts", + "build-staging": "webpack --config config/webpack/webpack.common.ts --env file=.env.staging && ts-node ./scripts/combine-web-sourcemaps.ts", + "build-adhoc": "webpack --config config/webpack/webpack.common.ts --env file=.env.adhoc && ts-node ./scripts/combine-web-sourcemaps.ts", + "desktop": "./scripts/set-pusher-suffix.sh && ts-node desktop/start.ts", + "desktop-build": "./scripts/build-desktop.sh production", + "desktop-build-staging": "./scripts/build-desktop.sh staging", "createDocsRoutes": "ts-node .github/scripts/createDocsRoutes.ts", "detectRedirectCycle": "ts-node .github/scripts/detectRedirectCycle.ts", - "desktop-build-adhoc": "scripts/build-desktop.sh adhoc", + "desktop-build-adhoc": "./scripts/build-desktop.sh adhoc", "ios-build": "fastlane ios build_unsigned", "android-build": "fastlane android build_local", "android-build-e2e": "bundle exec fastlane android build_e2e", @@ -37,7 +37,7 @@ "test": "TZ=utc NODE_OPTIONS=--experimental-vm-modules jest", "typecheck": "NODE_OPTIONS=--max_old_space_size=8192 tsc", "lint": "NODE_OPTIONS=--max_old_space_size=8192 eslint . --max-warnings=0 --cache --cache-location=node_modules/.cache/eslint", - "lint-changed": "eslint --fix $(git diff --diff-filter=AM --name-only main -- \"*.js\" \"*.ts\" \"*.tsx\")", + "lint-changed": "NODE_OPTIONS=--max_old_space_size=8192 eslint --max-warnings=0 --config ./.eslintrc.changed.js $(git diff --diff-filter=AM --name-only origin/main HEAD -- \"*.ts\" \"*.tsx\")", "lint-watch": "npx eslint-watch --watch --changed", "shellcheck": "./scripts/shellCheck.sh", "prettier": "prettier --write .", @@ -51,11 +51,11 @@ "analyze-packages": "ANALYZE_BUNDLE=true webpack --config config/webpack/webpack.common.ts --env file=.env.production", "symbolicate:android": "npx metro-symbolicate android/app/build/generated/sourcemaps/react/release/index.android.bundle.map", "symbolicate:ios": "npx metro-symbolicate main.jsbundle.map", - "symbolicate-release:ios": "scripts/release-profile.ts --platform=ios", - "symbolicate-release:android": "scripts/release-profile.ts --platform=android", - "symbolicate-release:web": "scripts/release-profile.ts --platform=web", - "symbolicate-profile": "scripts/symbolicate-profile.ts", - "combine-web-sourcemaps": "scripts/combine-web-sourcemaps.ts", + "symbolicate-release:ios": "./scripts/release-profile.ts --platform=ios", + "symbolicate-release:android": "./scripts/release-profile.ts --platform=android", + "symbolicate-release:web": "./scripts/release-profile.ts --platform=web", + "symbolicate-profile": "./scripts/symbolicate-profile.ts", + "combine-web-sourcemaps": "./scripts/combine-web-sourcemaps.ts", "test:e2e": "ts-node tests/e2e/testRunner.ts --config ./config.local.ts", "test:e2e:dev": "ts-node tests/e2e/testRunner.ts --config ./config.dev.ts", "gh-actions-unused-styles": "./.github/scripts/findUnusedKeys.sh", @@ -67,24 +67,18 @@ "web:prod": "http-server ./dist --cors" }, "dependencies": { - "@babel/plugin-proposal-private-methods": "^7.18.6", - "@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@dotlottie/react-player": "^1.6.3", - "@expensify/react-native-live-markdown": "0.1.120", + "@expensify/react-native-live-markdown": "0.1.143", "@expo/metro-runtime": "~3.2.3", "@formatjs/intl-datetimeformat": "^6.12.5", "@formatjs/intl-listformat": "^7.5.7", "@formatjs/intl-locale": "^4.0.0", "@formatjs/intl-numberformat": "^8.10.3", "@formatjs/intl-pluralrules": "^5.2.14", - "@fullstory/babel-plugin-annotate-react": "github:fullstorydev/fullstory-babel-plugin-annotate-react#ryanwang/react-native-web-demo", - "@fullstory/babel-plugin-react-native": "^1.2.1", "@fullstory/browser": "^2.0.3", "@fullstory/react-native": "^1.4.2", "@gorhom/portal": "^1.0.14", "@invertase/react-native-apple-authentication": "^2.2.2", - "@kie/act-js": "^2.6.2", - "@kie/mock-github": "2.0.1", "@onfido/react-native-sdk": "10.6.0", "@react-native-camera-roll/camera-roll": "7.4.0", "@react-native-clipboard/clipboard": "^1.13.2", @@ -102,7 +96,6 @@ "@react-ng/bounds-observer": "^0.2.1", "@rnmapbox/maps": "10.1.30", "@shopify/flash-list": "1.7.1", - "@types/mime-db": "^1.43.5", "@ua/react-native-airship": "19.2.1", "@vue/preload-webpack-plugin": "^2.0.0", "awesome-phonenumber": "^5.4.0", @@ -151,18 +144,17 @@ "react-native-fs": "^2.20.0", "react-native-gesture-handler": "2.18.0", "react-native-google-places-autocomplete": "2.5.6", - "react-native-haptic-feedback": "^2.2.0", + "react-native-haptic-feedback": "^2.3.1", "react-native-image-picker": "^7.0.3", "react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#cb392140db4953a283590d7cf93b4d0461baa2a9", "react-native-key-command": "^1.0.8", - "react-native-keyboard-controller": "^1.12.2", + "react-native-keyboard-controller": "1.12.7", "react-native-launch-arguments": "^4.0.2", - "react-native-linear-gradient": "^2.8.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", - "react-native-onyx": "2.0.66", + "react-native-onyx": "2.0.68", "react-native-pager-view": "6.4.1", - "react-native-pdf": "6.7.3", + "react-native-pdf": "6.7.5", "react-native-performance": "^5.1.0", "react-native-permissions": "^3.10.0", "react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#da50d2c5c54e268499047f9cc98b8df4196c1ddf", @@ -174,7 +166,7 @@ "react-native-render-html": "6.3.1", "react-native-safe-area-context": "4.10.9", "react-native-screens": "3.34.0", - "react-native-share": "^10.0.2", + "react-native-share": "11.0.2", "react-native-sound": "^0.11.2", "react-native-svg": "15.6.0", "react-native-tab-view": "^3.5.2", @@ -182,14 +174,12 @@ "react-native-view-shot": "3.8.0", "react-native-vision-camera": "4.0.0-beta.13", "react-native-web": "^0.19.12", - "react-native-web-linear-gradient": "^1.1.2", "react-native-web-sound": "^0.1.3", "react-native-webview": "13.8.6", "react-pdf": "^7.7.3", "react-plaid-link": "3.3.2", "react-web-config": "^1.0.0", "react-webcam": "^7.1.1", - "react-window": "^1.8.9", "semver": "^7.5.2", "xlsx": "file:vendor/xlsx-0.20.3.tgz" }, @@ -200,6 +190,8 @@ "@babel/parser": "^7.22.16", "@babel/plugin-proposal-class-properties": "^7.12.1", "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@babel/preset-env": "^7.20.0", "@babel/preset-flow": "^7.12.13", "@babel/preset-react": "^7.10.4", @@ -210,6 +202,7 @@ "@callstack/reassure-compare": "^1.0.0-rc.4", "@dword-design/eslint-plugin-import-alias": "^5.0.0", "@electron/notarize": "^2.1.0", + "@fullstory/babel-plugin-annotate-react": "^2.3.0", "@jest/globals": "^29.5.0", "@ngneat/falso": "^7.1.1", "@octokit/core": "4.0.4", @@ -242,6 +235,7 @@ "@types/js-yaml": "^4.0.5", "@types/lodash": "^4.14.195", "@types/mapbox-gl": "^2.7.13", + "@types/mime-db": "^1.43.5", "@types/node": "^20.11.5", "@types/pusher-js": "^5.1.0", "@types/react": "^18.2.6", @@ -290,7 +284,6 @@ "eslint-plugin-you-dont-need-lodash-underscore": "^6.14.0", "html-webpack-plugin": "^5.5.0", "http-server": "^14.1.1", - "husky": "^9.1.5", "jest": "29.4.1", "jest-circus": "29.4.1", "jest-cli": "29.4.1", @@ -326,8 +319,7 @@ "webpack-bundle-analyzer": "^4.5.0", "webpack-cli": "^5.0.4", "webpack-dev-server": "^5.0.4", - "webpack-merge": "^5.8.0", - "yaml": "^2.2.1" + "webpack-merge": "^5.8.0" }, "overrides": { "react-native": "0.75.2", diff --git a/patches/@expensify+react-native-live-markdown+0.1.120+001+intial.patch b/patches/@expensify+react-native-live-markdown+0.1.120+001+intial.patch deleted file mode 100644 index 4e59d206268e..000000000000 --- a/patches/@expensify+react-native-live-markdown+0.1.120+001+intial.patch +++ /dev/null @@ -1,48 +0,0 @@ -diff --git a/node_modules/@expensify/react-native-live-markdown/android/src/main/java/com/expensify/livemarkdown/LiveMarkdownModule.java b/node_modules/@expensify/react-native-live-markdown/android/src/main/java/com/expensify/livemarkdown/LiveMarkdownModule.java -index ed1428b..80641ce 100644 ---- a/node_modules/@expensify/react-native-live-markdown/android/src/main/java/com/expensify/livemarkdown/LiveMarkdownModule.java -+++ b/node_modules/@expensify/react-native-live-markdown/android/src/main/java/com/expensify/livemarkdown/LiveMarkdownModule.java -@@ -1,7 +1,6 @@ - package com.expensify.livemarkdown; - - import com.facebook.react.bridge.ReactApplicationContext; --import com.facebook.react.bridge.UIManager; - import com.facebook.react.fabric.FabricUIManager; - import com.facebook.react.uimanager.UIManagerHelper; - import com.facebook.react.uimanager.common.UIManagerType; -diff --git a/node_modules/@expensify/react-native-live-markdown/android/src/main/java/com/expensify/livemarkdown/MarkdownUtils.java b/node_modules/@expensify/react-native-live-markdown/android/src/main/java/com/expensify/livemarkdown/MarkdownUtils.java -index 7711d8b..0000caa 100644 ---- a/node_modules/@expensify/react-native-live-markdown/android/src/main/java/com/expensify/livemarkdown/MarkdownUtils.java -+++ b/node_modules/@expensify/react-native-live-markdown/android/src/main/java/com/expensify/livemarkdown/MarkdownUtils.java -@@ -1,6 +1,5 @@ - package com.expensify.livemarkdown; - --import static com.facebook.infer.annotation.ThreadConfined.UI; - - import android.content.res.AssetManager; - import android.text.SpannableStringBuilder; -@@ -8,10 +7,7 @@ import android.text.Spanned; - - import androidx.annotation.NonNull; - --import com.facebook.infer.annotation.Assertions; --import com.facebook.infer.annotation.ThreadConfined; --import com.facebook.react.bridge.UiThreadUtil; --import com.facebook.react.views.text.CustomLineHeightSpan; -+import com.facebook.react.views.text.internal.span.CustomLineHeightSpan; - import com.facebook.soloader.SoLoader; - - import org.json.JSONArray; -diff --git a/node_modules/@expensify/react-native-live-markdown/android/src/main/new_arch/CMakeLists.txt b/node_modules/@expensify/react-native-live-markdown/android/src/main/new_arch/CMakeLists.txt -index f5dfedf..1609c60 100644 ---- a/node_modules/@expensify/react-native-live-markdown/android/src/main/new_arch/CMakeLists.txt -+++ b/node_modules/@expensify/react-native-live-markdown/android/src/main/new_arch/CMakeLists.txt -@@ -42,6 +42,8 @@ target_link_libraries( - ReactAndroid::rrc_textinput - ReactAndroid::react_render_textlayoutmanager - ReactAndroid::react_render_imagemanager -+ ReactAndroid::reactnativejni -+ ReactAndroid::mapbufferjni - fabricjni - fbjni - folly_runtime diff --git a/patches/@expensify+react-native-live-markdown+0.1.120+002+text-layout-manager.patch b/patches/@expensify+react-native-live-markdown+0.1.120+002+text-layout-manager.patch deleted file mode 100644 index 24f327649253..000000000000 --- a/patches/@expensify+react-native-live-markdown+0.1.120+002+text-layout-manager.patch +++ /dev/null @@ -1,102 +0,0 @@ -diff --git a/node_modules/@expensify/react-native-live-markdown/android/src/main/java/com/expensify/livemarkdown/CustomMountingManager.java b/node_modules/@expensify/react-native-live-markdown/android/src/main/java/com/expensify/livemarkdown/CustomMountingManager.java -index 1b4381b..7e3aebe 100644 ---- a/node_modules/@expensify/react-native-live-markdown/android/src/main/java/com/expensify/livemarkdown/CustomMountingManager.java -+++ b/node_modules/@expensify/react-native-live-markdown/android/src/main/java/com/expensify/livemarkdown/CustomMountingManager.java -@@ -13,7 +13,6 @@ import android.text.TextPaint; - import androidx.annotation.NonNull; - import androidx.annotation.Nullable; - --import com.facebook.common.logging.FLog; - import com.facebook.react.bridge.ReactContext; - import com.facebook.react.bridge.ReadableMap; - import com.facebook.react.common.mapbuffer.MapBuffer; -@@ -21,8 +20,8 @@ import com.facebook.react.fabric.mounting.MountingManager; - import com.facebook.react.uimanager.PixelUtil; - import com.facebook.react.uimanager.ViewManagerRegistry; - import com.facebook.react.views.text.TextAttributeProps; --import com.facebook.react.views.text.TextInlineViewPlaceholderSpan; --import com.facebook.react.views.text.TextLayoutManagerMapBuffer; -+import com.facebook.react.views.text.internal.span.TextInlineViewPlaceholderSpan; -+import com.facebook.react.views.text.TextLayoutManager; - import com.facebook.yoga.YogaMeasureMode; - import com.facebook.yoga.YogaMeasureOutput; - -@@ -63,7 +62,7 @@ public class CustomMountingManager extends MountingManager { - @Nullable float[] attachmentsPositions) { - - Spannable text = -- TextLayoutManagerMapBuffer.getOrCreateSpannableForText(context, attributedString, null); -+ TextLayoutManager.getOrCreateSpannableForText(context, attributedString, null); - - if (text == null) { - return 0; -@@ -71,14 +70,14 @@ public class CustomMountingManager extends MountingManager { - - int textBreakStrategy = - TextAttributeProps.getTextBreakStrategy( -- paragraphAttributes.getString(TextLayoutManagerMapBuffer.PA_KEY_TEXT_BREAK_STRATEGY)); -+ paragraphAttributes.getString(TextLayoutManager.PA_KEY_TEXT_BREAK_STRATEGY)); - boolean includeFontPadding = -- paragraphAttributes.contains(TextLayoutManagerMapBuffer.PA_KEY_INCLUDE_FONT_PADDING) -- ? paragraphAttributes.getBoolean(TextLayoutManagerMapBuffer.PA_KEY_INCLUDE_FONT_PADDING) -+ paragraphAttributes.contains(TextLayoutManager.PA_KEY_INCLUDE_FONT_PADDING) -+ ? paragraphAttributes.getBoolean(TextLayoutManager.PA_KEY_INCLUDE_FONT_PADDING) - : DEFAULT_INCLUDE_FONT_PADDING; - int hyphenationFrequency = - TextAttributeProps.getHyphenationFrequency( -- paragraphAttributes.getString(TextLayoutManagerMapBuffer.PA_KEY_HYPHENATION_FREQUENCY)); -+ paragraphAttributes.getString(TextLayoutManager.PA_KEY_HYPHENATION_FREQUENCY)); - - // StaticLayout returns wrong metrics for the last line if it's empty, add something to the - // last line so it's measured correctly -@@ -89,13 +88,15 @@ public class CustomMountingManager extends MountingManager { - text = sb; - } - -+ Layout.Alignment alignment = TextLayoutManager.getTextAlignment(attributedString, text); -+ - markdownUtils.applyMarkdownFormatting((SpannableStringBuilder)text); - - BoringLayout.Metrics boring = BoringLayout.isBoring(text, sTextPaintInstance); - -- Class mapBufferClass = TextLayoutManagerMapBuffer.class; -+ Class mapBufferClass = TextLayoutManager.class; - try { -- Method createLayoutMethod = mapBufferClass.getDeclaredMethod("createLayout", Spannable.class, BoringLayout.Metrics.class, float.class, YogaMeasureMode.class, boolean.class, int.class, int.class); -+ Method createLayoutMethod = mapBufferClass.getDeclaredMethod("createLayout", Spannable.class, BoringLayout.Metrics.class, float.class, YogaMeasureMode.class, boolean.class, int.class, int.class, Layout.Alignment.class); - createLayoutMethod.setAccessible(true); - - Layout layout = (Layout)createLayoutMethod.invoke( -@@ -106,11 +107,12 @@ public class CustomMountingManager extends MountingManager { - widthYogaMeasureMode, - includeFontPadding, - textBreakStrategy, -- hyphenationFrequency); -+ hyphenationFrequency, -+ alignment); - - int maximumNumberOfLines = -- paragraphAttributes.contains(TextLayoutManagerMapBuffer.PA_KEY_MAX_NUMBER_OF_LINES) -- ? paragraphAttributes.getInt(TextLayoutManagerMapBuffer.PA_KEY_MAX_NUMBER_OF_LINES) -+ paragraphAttributes.contains(TextLayoutManager.PA_KEY_MAX_NUMBER_OF_LINES) -+ ? paragraphAttributes.getInt(TextLayoutManager.PA_KEY_MAX_NUMBER_OF_LINES) - : UNSET; - - int calculatedLineCount = -diff --git a/node_modules/@expensify/react-native-live-markdown/android/src/main/new_arch/CMakeLists.txt b/node_modules/@expensify/react-native-live-markdown/android/src/main/new_arch/CMakeLists.txt -index 1609c60..1888eea 100644 ---- a/node_modules/@expensify/react-native-live-markdown/android/src/main/new_arch/CMakeLists.txt -+++ b/node_modules/@expensify/react-native-live-markdown/android/src/main/new_arch/CMakeLists.txt -@@ -65,6 +65,12 @@ target_link_libraries( - yoga - android - log -+ mapbufferjni -+ reactnativejni -+ react_render_consistency -+ react_performance_timeline -+ react_render_observers_events -+ react_featureflags - ) - - target_compile_options( diff --git a/patches/@expensify+react-native-live-markdown+0.1.120+003+shadow-node.patch b/patches/@expensify+react-native-live-markdown+0.1.120+003+shadow-node.patch deleted file mode 100644 index d3ff41b29249..000000000000 --- a/patches/@expensify+react-native-live-markdown+0.1.120+003+shadow-node.patch +++ /dev/null @@ -1,72 +0,0 @@ -diff --git a/node_modules/@expensify/react-native-live-markdown/cpp/react/renderer/components/RNLiveMarkdownSpec/MarkdownTextInputDecoratorShadowNode.cpp b/node_modules/@expensify/react-native-live-markdown/cpp/react/renderer/components/RNLiveMarkdownSpec/MarkdownTextInputDecoratorShadowNode.cpp -index 104363d..9240e9e 100644 ---- a/node_modules/@expensify/react-native-live-markdown/cpp/react/renderer/components/RNLiveMarkdownSpec/MarkdownTextInputDecoratorShadowNode.cpp -+++ b/node_modules/@expensify/react-native-live-markdown/cpp/react/renderer/components/RNLiveMarkdownSpec/MarkdownTextInputDecoratorShadowNode.cpp -@@ -11,7 +11,7 @@ namespace react { - extern const char MarkdownTextInputDecoratorViewComponentName[] = - "MarkdownTextInputDecoratorView"; - --const ShadowNodeFragment::Value -+const OwningShadowNodeFragment - MarkdownTextInputDecoratorShadowNode::updateFragmentState( - ShadowNodeFragment const &fragment, - ShadowNodeFamily::Shared const &family) { -@@ -24,12 +24,12 @@ MarkdownTextInputDecoratorShadowNode::updateFragmentState( - // propagated on every clone we need it to clear the reference in the registry - // when the view is removed from window it cannot be done in the destructor, - // as multiple shadow nodes for the same family may be created -- return ShadowNodeFragment::Value({ -+ return OwningShadowNodeFragment{ - .props = fragment.props, - .children = fragment.children, - .state = - std::make_shared(newStateData, *fragment.state), -- }); -+ }; - } - - } // namespace react -diff --git a/node_modules/@expensify/react-native-live-markdown/cpp/react/renderer/components/RNLiveMarkdownSpec/MarkdownTextInputDecoratorShadowNode.h b/node_modules/@expensify/react-native-live-markdown/cpp/react/renderer/components/RNLiveMarkdownSpec/MarkdownTextInputDecoratorShadowNode.h -index 294e0d3..597752c 100644 ---- a/node_modules/@expensify/react-native-live-markdown/cpp/react/renderer/components/RNLiveMarkdownSpec/MarkdownTextInputDecoratorShadowNode.h -+++ b/node_modules/@expensify/react-native-live-markdown/cpp/react/renderer/components/RNLiveMarkdownSpec/MarkdownTextInputDecoratorShadowNode.h -@@ -11,6 +11,20 @@ - namespace facebook { - namespace react { - -+struct OwningShadowNodeFragment { -+ Props::Shared props; -+ ShadowNode::SharedListOfShared children; -+ State::Shared state; -+ -+ operator ShadowNodeFragment() const { -+ return ShadowNodeFragment { -+ .props = props, -+ .children = children, -+ .state = state -+ }; -+ } -+}; -+ - JSI_EXPORT extern const char MarkdownTextInputDecoratorViewComponentName[]; - - class JSI_EXPORT MarkdownTextInputDecoratorShadowNode final -@@ -22,8 +36,7 @@ public: - MarkdownTextInputDecoratorShadowNode(ShadowNodeFragment const &fragment, - ShadowNodeFamily::Shared const &family, - ShadowNodeTraits traits) -- : ConcreteViewShadowNode(static_cast( -- updateFragmentState(fragment, family)), -+ : ConcreteViewShadowNode(updateFragmentState(fragment, family), - family, traits) {} - - MarkdownTextInputDecoratorShadowNode(ShadowNode const &sourceShadowNode, -@@ -37,7 +50,7 @@ public: - } - - private: -- static const ShadowNodeFragment::Value -+ static const OwningShadowNodeFragment - updateFragmentState(ShadowNodeFragment const &fragment, - ShadowNodeFamily::Shared const &family); - }; diff --git a/patches/@expensify+react-native-live-markdown+0.1.120+004+hybrid-app.patch b/patches/@expensify+react-native-live-markdown+0.1.120+004+hybrid-app.patch deleted file mode 100644 index 00f87066c9fa..000000000000 --- a/patches/@expensify+react-native-live-markdown+0.1.120+004+hybrid-app.patch +++ /dev/null @@ -1,18 +0,0 @@ -diff --git a/node_modules/@expensify/react-native-live-markdown/RNLiveMarkdown.podspec b/node_modules/@expensify/react-native-live-markdown/RNLiveMarkdown.podspec -index b1620ad..b3ea39c 100644 ---- a/node_modules/@expensify/react-native-live-markdown/RNLiveMarkdown.podspec -+++ b/node_modules/@expensify/react-native-live-markdown/RNLiveMarkdown.podspec -@@ -23,10 +23,10 @@ Pod::Spec.new do |s| - install_modules_dependencies(s) - - if ENV['USE_FRAMEWORKS'] && ENV['RCT_NEW_ARCH_ENABLED'] -- add_dependency(s, "React-Fabric", :additional_framework_paths => [ -+ add_dependency(s, "React-FabricComponents", :additional_framework_paths => [ - "react/renderer/textlayoutmanager/platform/ios", -- "react/renderer/components/textinput/iostextinput", -- ]) -+ "react/renderer/components/textinput/platform/ios", -+ ]); - end - - s.subspec "common" do |ss| diff --git a/patches/react-native-haptic-feedback+2.2.0.patch b/patches/react-native-haptic-feedback+2.2.0.patch deleted file mode 100644 index 4fb61b430869..000000000000 --- a/patches/react-native-haptic-feedback+2.2.0.patch +++ /dev/null @@ -1,30 +0,0 @@ -diff --git a/node_modules/react-native-haptic-feedback/RNReactNativeHapticFeedback.podspec b/node_modules/react-native-haptic-feedback/RNReactNativeHapticFeedback.podspec -index e692f2d..9dedd9b 100644 ---- a/node_modules/react-native-haptic-feedback/RNReactNativeHapticFeedback.podspec -+++ b/node_modules/react-native-haptic-feedback/RNReactNativeHapticFeedback.podspec -@@ -17,24 +17,7 @@ Pod::Spec.new do |s| - s.source_files = "ios/**/*.{h,m,mm}" - s.requires_arc = true - -- s.dependency 'React-Core' -- -- # This guard prevent to install the dependencies when we run `pod install` in the old architecture. -- if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then -- folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32' -- -- s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1" -- s.pod_target_xcconfig = { -- "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"", -- "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" -- } -- -- s.dependency "React-Codegen" -- s.dependency "RCT-Folly" -- s.dependency "RCTRequired" -- s.dependency "RCTTypeSafety" -- s.dependency "ReactCommon/turbomodule/core" -- end -+ install_modules_dependencies(s) - end - - diff --git a/patches/react-native-haptic-feedback+2.3.1.patch b/patches/react-native-haptic-feedback+2.3.1.patch new file mode 100644 index 000000000000..799bdaf7e53e --- /dev/null +++ b/patches/react-native-haptic-feedback+2.3.1.patch @@ -0,0 +1,56 @@ +diff --git a/node_modules/react-native-haptic-feedback/ios/RNHapticFeedback/RNHapticFeedback.h b/node_modules/react-native-haptic-feedback/ios/RNHapticFeedback/RNHapticFeedback.h +index c1498b9..250df1f 100644 +--- a/node_modules/react-native-haptic-feedback/ios/RNHapticFeedback/RNHapticFeedback.h ++++ b/node_modules/react-native-haptic-feedback/ios/RNHapticFeedback/RNHapticFeedback.h +@@ -1,5 +1,5 @@ + #ifdef RCT_NEW_ARCH_ENABLED +-#import "RNHapticFeedbackSpec.h" ++#import + + @interface RNHapticFeedback : NSObject + #else +diff --git a/node_modules/react-native-haptic-feedback/ios/RNHapticFeedback/RNHapticFeedbackSpec.h b/node_modules/react-native-haptic-feedback/ios/RNHapticFeedback/RNHapticFeedbackSpec.h +deleted file mode 100644 +index 6f0f81d..0000000 +--- a/node_modules/react-native-haptic-feedback/ios/RNHapticFeedback/RNHapticFeedbackSpec.h ++++ /dev/null +@@ -1,15 +0,0 @@ +-// +-// RNHapticFeedbackSpec.h +-// RNHapticFeedback +-// +-// Created by Michael Kuczera on 05.08.24. +-// Copyright © 2024 Facebook. All rights reserved. +-// +-#import +- +-@protocol NativeHapticFeedbackSpec +- +-// Indicates whether the device supports haptic feedback +-- (Boolean)supportsHaptic; +- +-@end +diff --git a/node_modules/react-native-haptic-feedback/package.json b/node_modules/react-native-haptic-feedback/package.json +index 86dfaa4..9cec8e4 100644 +--- a/node_modules/react-native-haptic-feedback/package.json ++++ b/node_modules/react-native-haptic-feedback/package.json +@@ -6,18 +6,7 @@ + "source": "src/index.ts", + "main": "./lib/commonjs/index.js", + "module": "./lib/module/index.js", +- "exports": { +- ".": { +- "import": { +- "types": "./lib/typescript/module/src/index.d.ts", +- "default": "./lib/module/index.js" +- }, +- "require": { +- "types": "./lib/typescript/commonjs/src/index.d.ts", +- "default": "./lib/commonjs/index.js" +- } +- } +- }, ++ "types": "./lib/typescript/module/src/index.d.ts", + "scripts": { + "typecheck": "tsc --noEmit --project tsconfig.test.json", + "test": "jest", diff --git a/patches/react-native-keyboard-controller+1.12.2+002+rn-75-fixes.patch b/patches/react-native-keyboard-controller+1.12.2+002+rn-75-fixes.patch deleted file mode 100644 index f7ab542a2a2b..000000000000 --- a/patches/react-native-keyboard-controller+1.12.2+002+rn-75-fixes.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/node_modules/react-native-keyboard-controller/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ThemedReactContext.kt b/node_modules/react-native-keyboard-controller/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ThemedReactContext.kt -index 50252f0..28a70d6 100644 ---- a/node_modules/react-native-keyboard-controller/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ThemedReactContext.kt -+++ b/node_modules/react-native-keyboard-controller/android/src/main/java/com/reactnativekeyboardcontroller/extensions/ThemedReactContext.kt -@@ -13,7 +13,7 @@ val ThemedReactContext.rootView: View? - - fun ThemedReactContext?.dispatchEvent(viewId: Int, event: Event<*>) { - val eventDispatcher: EventDispatcher? = -- UIManagerHelper.getEventDispatcherForReactTag(this, viewId) -+ UIManagerHelper.getEventDispatcherForReactTag(this!!, viewId) - eventDispatcher?.dispatchEvent(event) - } - diff --git a/patches/react-native-keyboard-controller+1.12.2+001+initial.patch b/patches/react-native-keyboard-controller+1.12.7.patch similarity index 100% rename from patches/react-native-keyboard-controller+1.12.2+001+initial.patch rename to patches/react-native-keyboard-controller+1.12.7.patch diff --git a/patches/react-native-pdf+6.7.3.patch b/patches/react-native-pdf+6.7.3.patch deleted file mode 100644 index 0f0f270cefd1..000000000000 --- a/patches/react-native-pdf+6.7.3.patch +++ /dev/null @@ -1,53 +0,0 @@ -diff --git a/node_modules/react-native-pdf/react-native-pdf.podspec b/node_modules/react-native-pdf/react-native-pdf.podspec -index fb36140..5d5f19e 100644 ---- a/node_modules/react-native-pdf/react-native-pdf.podspec -+++ b/node_modules/react-native-pdf/react-native-pdf.podspec -@@ -17,24 +17,11 @@ Pod::Spec.new do |s| - s.framework = "PDFKit" - - if fabric_enabled -- folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32' -- -- s.pod_target_xcconfig = { -- 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/boost" "$(PODS_ROOT)/boost-for-react-native" "$(PODS_ROOT)/RCT-Folly"', -- "CLANG_CXX_LANGUAGE_STANDARD" => "c++17", -- } - s.platforms = { ios: '11.0', tvos: '11.0' } -- s.compiler_flags = folly_compiler_flags + ' -DRCT_NEW_ARCH_ENABLED' - s.source_files = 'ios/**/*.{h,m,mm,cpp}' - s.requires_arc = true - -- s.dependency "React" -- s.dependency "React-RCTFabric" -- s.dependency "React-Codegen" -- s.dependency "RCT-Folly" -- s.dependency "RCTRequired" -- s.dependency "RCTTypeSafety" -- s.dependency "ReactCommon/turbomodule/core" -+ install_modules_dependencies(s) - else - s.platform = :ios, '8.0' - s.source_files = 'ios/**/*.{h,m,mm}' -diff --git a/node_modules/react-native-pdf/index.js b/node_modules/react-native-pdf/index.js -index c05de52..bea7af8 100644 ---- a/node_modules/react-native-pdf/index.js -+++ b/node_modules/react-native-pdf/index.js -@@ -367,11 +367,17 @@ export default class Pdf extends Component { - message[4] = message.splice(4).join('|'); - } - if (message[0] === 'loadComplete') { -+ let tableContents; -+ try { -+ tableContents = message[4]&&JSON.parse(message[4]); -+ } catch(e) { -+ tableContents = message[4]; -+ } - this.props.onLoadComplete && this.props.onLoadComplete(Number(message[1]), this.state.path, { - width: Number(message[2]), - height: Number(message[3]), - }, -- message[4]&&JSON.parse(message[4])); -+ tableContents); - } else if (message[0] === 'pageChanged') { - this.props.onPageChanged && this.props.onPageChanged(Number(message[1]), Number(message[2])); - } else if (message[0] === 'error') { diff --git a/patches/react-native-pdf+6.7.5.patch b/patches/react-native-pdf+6.7.5.patch new file mode 100644 index 000000000000..0cdcf4d5b0c9 --- /dev/null +++ b/patches/react-native-pdf+6.7.5.patch @@ -0,0 +1,12 @@ +diff --git a/node_modules/react-native-pdf/fabric/RNPDFPdfNativeComponent.js b/node_modules/react-native-pdf/fabric/RNPDFPdfNativeComponent.js +index 596d796..4e47061 100644 +--- a/node_modules/react-native-pdf/fabric/RNPDFPdfNativeComponent.js ++++ b/node_modules/react-native-pdf/fabric/RNPDFPdfNativeComponent.js +@@ -22,6 +22,7 @@ + enablePaging: ?boolean, + enableRTL: ?boolean, + enableAnnotationRendering: ?boolean, ++ enableDoubleTapZoom: ?boolean, + showsHorizontalScrollIndicator: ?boolean, + showsVerticalScrollIndicator: ?boolean, + enableAntialiasing: ?boolean, diff --git a/patches/react-native-share+10.0.2+001+hybrid-app.patch b/patches/react-native-share+10.0.2+001+hybrid-app.patch deleted file mode 100644 index 13dcc1e8438b..000000000000 --- a/patches/react-native-share+10.0.2+001+hybrid-app.patch +++ /dev/null @@ -1,26 +0,0 @@ -diff --git a/node_modules/react-native-share/RNShare.podspec b/node_modules/react-native-share/RNShare.podspec -index 124a721..636a1f7 100644 ---- a/node_modules/react-native-share/RNShare.podspec -+++ b/node_modules/react-native-share/RNShare.podspec -@@ -20,20 +20,6 @@ Pod::Spec.new do |s| - - s.ios.weak_framework = 'LinkPresentation' - -- if ENV["RCT_NEW_ARCH_ENABLED"] == "1" -- s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1" -- s.pod_target_xcconfig = { -- "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"", -- "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", -- "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" -- } -- -- s.dependency "React-Codegen" -- s.dependency "React-RCTFabric" -- s.dependency "RCT-Folly" -- s.dependency "RCTRequired" -- s.dependency "RCTTypeSafety" -- s.dependency "ReactCommon/turbomodule/core" -- end -+ install_modules_dependencies(s) - - end diff --git a/src/CONST.ts b/src/CONST.ts index cd4d2b24e97a..c00b33be1c31 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -111,16 +111,16 @@ const onboardingEmployerOrSubmitMessage: OnboardingMessageType = { 'Then, send your request and wait for that sweet “Cha-ching!” when it’s complete.', }, { - type: 'enableWallet', + type: 'addBankAccount', autoCompleted: false, - title: 'Enable your wallet', + title: 'Add personal bank account', description: - 'You’ll need to *enable your Expensify Wallet* to get paid back. Don’t worry, it’s easy!\n' + + 'You’ll need to add your personal bank account to get paid back. Don’t worry, it’s easy!\n' + '\n' + - 'Here’s how to set up your wallet:\n' + + 'Here’s how to set up your bank account:\n' + '\n' + '1. Click your profile picture.\n' + - '2. Click *Wallet* > *Enable wallet*.\n' + + '2. Click *Wallet* > *Bank accounts* > *+ Add bank account*.\n' + '3. Connect your bank account.\n' + '\n' + 'Once that’s done, you can request money from anyone and get paid back right into your personal bank account.', @@ -189,6 +189,8 @@ const CONST = { }, // Multiplier for gyroscope animation in order to make it a bit more subtle ANIMATION_GYROSCOPE_VALUE: 0.4, + ANIMATION_PAY_BUTTON_DURATION: 200, + ANIMATION_PAY_BUTTON_HIDE_DELAY: 1000, BACKGROUND_IMAGE_TRANSITION_DURATION: 1000, SCREEN_TRANSITION_END_TIMEOUT: 1000, ARROW_HIDE_DELAY: 3000, @@ -1415,6 +1417,7 @@ const CONST = { LHN_SKELETON_VIEW_ITEM_HEIGHT: 64, SEARCH_SKELETON_VIEW_ITEM_HEIGHT: 108, EXPENSIFY_PARTNER_NAME: 'expensify.com', + EXPENSIFY_MERCHANT: 'Expensify, Inc.', EMAIL: { ACCOUNTING: 'accounting@expensify.com', ADMIN: 'admin@expensify.com', @@ -2208,6 +2211,7 @@ const CONST = { REMOVE: 'remove', MAKE_MEMBER: 'makeMember', MAKE_ADMIN: 'makeAdmin', + MAKE_AUDITOR: 'makeAuditor', }, BULK_ACTION_TYPES: { DELETE: 'delete', @@ -2340,6 +2344,8 @@ const CONST = { NETSUITE_SYNC_UPDATE_DATA: 'netSuiteSyncUpdateConnectionData', NETSUITE_SYNC_NETSUITE_REIMBURSED_REPORTS: 'netSuiteSyncNetSuiteReimbursedReports', NETSUITE_SYNC_EXPENSIFY_REIMBURSED_REPORTS: 'netSuiteSyncExpensifyReimbursedReports', + NETSUITE_SYNC_IMPORT_VENDORS_TITLE: 'netSuiteImportVendorsTitle', + NETSUITE_SYNC_IMPORT_CUSTOM_LISTS_TITLE: 'netSuiteImportCustomListsTitle', SAGE_INTACCT_SYNC_CHECK_CONNECTION: 'intacctCheckConnection', SAGE_INTACCT_SYNC_IMPORT_TITLE: 'intacctImportTitle', SAGE_INTACCT_SYNC_IMPORT_DATA: 'intacctImportData', @@ -2488,6 +2494,90 @@ const CONST = { RESTRICT: 'corporate', ALLOW: 'personal', }, + EXPORT_CARD_TYPES: { + /** + * Name of Card NVP for QBO custom export accounts + */ + NVP_QUICKBOOKS_ONLINE_EXPORT_ACCOUNT: 'quickbooks_online_export_account', + NVP_QUICKBOOKS_ONLINE_EXPORT_ACCOUNT_DEBIT: 'quickbooks_online_export_account_debit', + + /** + * Name of Card NVP for NetSuite custom export accounts + */ + NVP_NETSUITE_EXPORT_ACCOUNT: 'netsuite_export_payable_account', + + /** + * Name of Card NVP for NetSuite custom vendors + */ + NVP_NETSUITE_EXPORT_VENDOR: 'netsuite_export_vendor', + + /** + * Name of Card NVP for Xero custom export accounts + */ + NVP_XERO_EXPORT_BANK_ACCOUNT: 'xero_export_bank_account', + + /** + * Name of Card NVP for Intacct custom export accounts + */ + NVP_INTACCT_EXPORT_CHARGE_CARD: 'intacct_export_charge_card', + + /** + * Name of card NVP for Intacct custom vendors + */ + NVP_INTACCT_EXPORT_VENDOR: 'intacct_export_vendor', + + /** + * Name of Card NVP for QuickBooks Desktop custom export accounts + */ + NVP_QUICKBOOKS_DESKTOP_EXPORT_ACCOUNT_CREDIT: 'quickbooks_desktop_export_account_credit', + + /** + * Name of Card NVP for QuickBooks Desktop custom export accounts + */ + NVP_FINANCIALFORCE_EXPORT_VENDOR: 'financialforce_export_vendor', + }, + EXPORT_CARD_POLICY_TYPES: { + /** + * Name of Card NVP for QBO custom export accounts + */ + NVP_QUICKBOOKS_ONLINE_EXPORT_ACCOUNT_POLICY_ID: 'quickbooks_online_export_account_policy_id', + NVP_QUICKBOOKS_ONLINE_EXPORT_ACCOUNT_DEBIT_POLICY_ID: 'quickbooks_online_export_account_debit_policy_id', + + /** + * Name of Card NVP for NetSuite custom export accounts + */ + NVP_NETSUITE_EXPORT_ACCOUNT_POLICY_ID: 'netsuite_export_payable_account_policy_id', + + /** + * Name of Card NVP for NetSuite custom vendors + */ + NVP_NETSUITE_EXPORT_VENDOR_POLICY_ID: 'netsuite_export_vendor_policy_id', + + /** + * Name of Card NVP for Xero custom export accounts + */ + NVP_XERO_EXPORT_BANK_ACCOUNT_POLICY_ID: 'xero_export_bank_account_policy_id', + + /** + * Name of Card NVP for Intacct custom export accounts + */ + NVP_INTACCT_EXPORT_CHARGE_CARD_POLICY_ID: 'intacct_export_charge_card_policy_id', + + /** + * Name of card NVP for Intacct custom vendors + */ + NVP_INTACCT_EXPORT_VENDOR_POLICY_ID: 'intacct_export_vendor_policy_id', + + /** + * Name of Card NVP for QuickBooks Desktop custom export accounts + */ + NVP_QUICKBOOKS_DESKTOP_EXPORT_ACCOUNT_CREDIT_POLICY_ID: 'quickbooks_desktop_export_account_credit_policy_id', + + /** + * Name of Card NVP for QuickBooks Desktop custom export accounts + */ + NVP_FINANCIALFORCE_EXPORT_VENDOR_POLICY_ID: 'financialforce_export_vendor_policy_id', + }, }, AVATAR_ROW_SIZE: { DEFAULT: 4, @@ -2544,10 +2634,8 @@ const CONST = { ATTACHMENT_ID: /chat-attachments\/(\d+)/, HAS_COLON_ONLY_AT_THE_BEGINNING: /^:[^:]+$/, HAS_AT_MOST_TWO_AT_SIGNS: /^@[^@]*@?[^@]*$/, - EMPTY_COMMENT: /^(\s)*$/, SPECIAL_CHAR: /[,/?"{}[\]()&^%;`$=#<>!*]/g, - FIRST_SPACE: /.+?(?=\s)/, get SPECIAL_CHAR_OR_EMOJI() { @@ -2565,33 +2653,24 @@ const CONST = { }, MERGED_ACCOUNT_PREFIX: /^(MERGED_\d+@)/, - ROUTES: { VALIDATE_LOGIN: /\/v($|(\/\/*))/, UNLINK_LOGIN: /\/u($|(\/\/*))/, REDUNDANT_SLASHES: /(\/{2,})|(\/$)/g, }, - TIME_STARTS_01: /^01:\d{2} [AP]M$/, TIME_FORMAT: /^\d{2}:\d{2} [AP]M$/, DATE_TIME_FORMAT: /^\d{2}-\d{2} \d{2}:\d{2} [AP]M$/, ILLEGAL_FILENAME_CHARACTERS: /\/|<|>|\*|"|:|\?|\\|\|/g, - ENCODE_PERCENT_CHARACTER: /%(25)+/g, - INVISIBLE_CHARACTERS_GROUPS: /[\p{C}\p{Z}]/gu, - OTHER_INVISIBLE_CHARACTERS: /[\u3164]/g, - REPORT_FIELD_TITLE: /{report:([a-zA-Z]+)}/g, - PATH_WITHOUT_POLICY_ID: /\/w\/[a-zA-Z0-9]+(\/|$)/, - POLICY_ID_FROM_PATH: /\/w\/([a-zA-Z0-9]+)(\/|$)/, - SHORT_MENTION: new RegExp(`@[\\w\\-\\+\\'#@]+(?:\\.[\\w\\-\\'\\+]+)*(?![^\`]*\`)`, 'gim'), - REPORT_ID_FROM_PATH: /\/r\/(\d+)/, + DISTANCE_MERCHANT: /^[0-9.]+ \w+ @ (-|-\()?[^0-9.\s]{1,3} ?[0-9.]+\)? \/ \w+$/, get EXPENSIFY_POLICY_DOMAIN_NAME() { return new RegExp(`${EXPENSIFY_POLICY_DOMAIN}([a-zA-Z0-9]+)\\${EXPENSIFY_POLICY_DOMAIN_EXTENSION}`); @@ -3960,70 +4039,6 @@ const CONST = { EXPENSIFY_LOGO_MARGIN_RATIO: 0.03, }, - /** - * Acceptable values for the `accessibilityRole` prop on react native components. - * - * **IMPORTANT:** Do not use with the `role` prop as it can cause errors. - * - * @deprecated ACCESSIBILITY_ROLE is deprecated. Please use CONST.ROLE instead. - */ - ACCESSIBILITY_ROLE: { - /** - * @deprecated Please stop using the accessibilityRole prop and use the role prop instead. - */ - BUTTON: 'button', - - /** - * @deprecated Please stop using the accessibilityRole prop and use the role prop instead. - */ - LINK: 'link', - - /** - * @deprecated Please stop using the accessibilityRole prop and use the role prop instead. - */ - MENUITEM: 'menuitem', - - /** - * @deprecated Please stop using the accessibilityRole prop and use the role prop instead. - */ - TEXT: 'text', - - /** - * @deprecated Please stop using the accessibilityRole prop and use the role prop instead. - */ - RADIO: 'radio', - - /** - * @deprecated Please stop using the accessibilityRole prop and use the role prop instead. - */ - IMAGEBUTTON: 'imagebutton', - - /** - * @deprecated Please stop using the accessibilityRole prop and use the role prop instead. - */ - CHECKBOX: 'checkbox', - - /** - * @deprecated Please stop using the accessibilityRole prop and use the role prop instead. - */ - SWITCH: 'switch', - - /** - * @deprecated Please stop using the accessibilityRole prop and use the role prop instead. - */ - ADJUSTABLE: 'adjustable', - - /** - * @deprecated Please stop using the accessibilityRole prop and use the role prop instead. - */ - IMAGE: 'image', - - /** - * @deprecated Please stop using the accessibilityRole prop and use the role prop instead. - */ - TEXTBOX: 'textbox', - }, - /** * Acceptable values for the `role` attribute on react native components. * @@ -4527,6 +4542,25 @@ const CONST = { '\n' + `[Take me to workspace category settings](${workspaceCategoriesLink}).`, }, + { + type: 'setupTags', + autoCompleted: false, + title: 'Set up tags (optional)', + description: ({workspaceMoreFeaturesLink}) => + 'Tags can be used if you want more details with every expense. Use tags for projects, clients, locations, departments, and more. If you need multiple levels of tags you can upgrade to a control plan.\n' + + '\n' + + '*Here’s how to set up tags:*\n' + + '\n' + + '1. Click your profile picture.\n' + + '2. Go to Workspaces.\n' + + '3. Select your workspace.\n' + + '4. Click More features.\n' + + '5. Enable tags.\n' + + '6. Navigate to Tags in the workspace editor.\n' + + '7. In Tags, click + Add tag to make your own.\n' + + '\n' + + `*[Take me to more features](${workspaceMoreFeaturesLink})*`, + }, { type: 'addExpenseApprovals', autoCompleted: false, @@ -4638,19 +4672,19 @@ const CONST = { 'Feel free to add more details if you want, or just send it off. Let’s get you paid back!', }, { - type: 'enableWallet', + type: 'addBankAccount', autoCompleted: false, - title: 'Enable your wallet', + title: 'Add personal bank account', description: - 'You’ll need to *enable your Expensify Wallet* to get paid back. Don’t worry, it’s easy!\n' + + 'You’ll need to add your personal bank account to get paid back. Don’t worry, it’s easy!\n' + '\n' + - 'Here’s how to enable your wallet:\n' + + 'Here’s how to set up your bank account:\n' + '\n' + '1. Click your profile picture.\n' + - '2. *Click Wallet* > *Enable wallet*.\n' + - '3. Add your bank account.\n' + + '2. Click *Wallet* > *Bank accounts* > *+ Add bank account*.\n' + + '3. Connect your bank account.\n' + '\n' + - 'Once that’s done, you can request money from anyone and get paid right into your personal bank account.', + 'Once that’s done, you can request money from anyone and get paid back right into your personal bank account.', }, ], }, diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 1d33b6892d51..38affd97c637 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -215,6 +215,9 @@ const ONYXKEYS = { /** The NVP containing all information related to educational tooltip in workspace chat */ NVP_WORKSPACE_TOOLTIP: 'workspaceTooltip', + /** Whether to hide save search rename tooltip */ + NVP_SHOULD_HIDE_SAVED_SEARCH_RENAME_TOOLTIP: 'nvp_should_hide_saved_search_rename_tooltip', + /** Whether to hide gbr tooltip */ NVP_SHOULD_HIDE_GBR_TOOLTIP: 'nvp_should_hide_gbr_tooltip', @@ -424,6 +427,9 @@ const ONYXKEYS = { /** Stores the route to open after changing app permission from settings */ LAST_ROUTE: 'lastRoute', + /** Stores the information about the saved searches */ + SAVED_SEARCHES: 'nvp_savedSearches', + /** Stores recently used currencies */ RECENTLY_USED_CURRENCIES: 'nvp_recentlyUsedCurrencies', @@ -530,6 +536,8 @@ const ONYXKEYS = { WORKSPACE_TAX_CUSTOM_NAME_DRAFT: 'workspaceTaxCustomNameDraft', WORKSPACE_COMPANY_CARD_FEED_NAME: 'workspaceCompanyCardFeedName', WORKSPACE_COMPANY_CARD_FEED_NAME_DRAFT: 'workspaceCompanyCardFeedNameDraft', + EDIT_WORKSPACE_COMPANY_CARD_NAME_FORM: 'editCompanyCardName', + EDIT_WORKSPACE_COMPANY_CARD_NAME_DRAFT_FORM: 'editCompanyCardNameDraft', WORKSPACE_REPORT_FIELDS_FORM: 'workspaceReportFieldForm', WORKSPACE_REPORT_FIELDS_FORM_DRAFT: 'workspaceReportFieldFormDraft', POLICY_CREATE_DISTANCE_RATE_FORM: 'policyCreateDistanceRateForm', @@ -666,6 +674,8 @@ const ONYXKEYS = { SAGE_INTACCT_DIMENSION_TYPE_FORM_DRAFT: 'sageIntacctDimensionTypeFormDraft', SEARCH_ADVANCED_FILTERS_FORM: 'searchAdvancedFiltersForm', SEARCH_ADVANCED_FILTERS_FORM_DRAFT: 'searchAdvancedFiltersFormDraft', + SEARCH_SAVED_SEARCH_RENAME_FORM: 'searchSavedSearchRenameForm', + SEARCH_SAVED_SEARCH_RENAME_FORM_DRAFT: 'searchSavedSearchRenameFormDraft', TEXT_PICKER_MODAL_FORM: 'textPickerModalForm', TEXT_PICKER_MODAL_FORM_DRAFT: 'textPickerModalFormDraft', RULES_CUSTOM_NAME_MODAL_FORM: 'rulesCustomNameModalForm', @@ -695,6 +705,7 @@ type OnyxFormValuesMapping = { [ONYXKEYS.FORMS.WORKSPACE_RATE_AND_UNIT_FORM]: FormTypes.WorkspaceRateAndUnitForm; [ONYXKEYS.FORMS.WORKSPACE_TAX_CUSTOM_NAME]: FormTypes.WorkspaceTaxCustomName; [ONYXKEYS.FORMS.WORKSPACE_COMPANY_CARD_FEED_NAME]: FormTypes.WorkspaceCompanyCardFeedName; + [ONYXKEYS.FORMS.EDIT_WORKSPACE_COMPANY_CARD_NAME_FORM]: FormTypes.WorkspaceCompanyCardEditName; [ONYXKEYS.FORMS.WORKSPACE_REPORT_FIELDS_FORM]: FormTypes.WorkspaceReportFieldForm; [ONYXKEYS.FORMS.WORKSPACE_CATEGORY_DESCRIPTION_HINT_FORM]: FormTypes.WorkspaceCategoryDescriptionHintForm; [ONYXKEYS.FORMS.WORKSPACE_CATEGORY_FLAG_AMOUNTS_OVER_FORM]: FormTypes.WorkspaceCategoryFlagAmountsOverForm; @@ -774,6 +785,7 @@ type OnyxFormValuesMapping = { [ONYXKEYS.FORMS.RULES_REQUIRED_RECEIPT_AMOUNT_FORM]: FormTypes.RulesRequiredReceiptAmountForm; [ONYXKEYS.FORMS.RULES_MAX_EXPENSE_AMOUNT_FORM]: FormTypes.RulesMaxExpenseAmountForm; [ONYXKEYS.FORMS.RULES_MAX_EXPENSE_AGE_FORM]: FormTypes.RulesMaxExpenseAgeForm; + [ONYXKEYS.FORMS.SEARCH_SAVED_SEARCH_RENAME_FORM]: FormTypes.SearchSavedSearchRenameForm; }; type OnyxFormDraftValuesMapping = { @@ -839,6 +851,7 @@ type OnyxValuesMapping = { // ONYXKEYS.NVP_TRYNEWDOT is HybridApp onboarding data [ONYXKEYS.NVP_TRYNEWDOT]: OnyxTypes.TryNewDot; + [ONYXKEYS.SAVED_SEARCHES]: OnyxTypes.SaveSearch[]; [ONYXKEYS.RECENTLY_USED_CURRENCIES]: string[]; [ONYXKEYS.ACTIVE_CLIENTS]: string[]; [ONYXKEYS.DEVICE_ID]: string; @@ -973,6 +986,7 @@ type OnyxValuesMapping = { [ONYXKEYS.APPROVAL_WORKFLOW]: OnyxTypes.ApprovalWorkflowOnyx; [ONYXKEYS.IMPORTED_SPREADSHEET]: OnyxTypes.ImportedSpreadsheet; [ONYXKEYS.LAST_ROUTE]: string; + [ONYXKEYS.NVP_SHOULD_HIDE_SAVED_SEARCH_RENAME_TOOLTIP]: boolean; }; type OnyxValues = OnyxValuesMapping & OnyxCollectionValuesMapping & OnyxFormValuesMapping & OnyxFormDraftValuesMapping; diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 2b6268c05b3a..27504998c49c 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -37,6 +37,10 @@ const ROUTES = { route: 'search', getRoute: ({query}: {query: SearchQueryString}) => `search?q=${encodeURIComponent(query)}` as const, }, + SEARCH_SAVED_SEARCH_RENAME: { + route: 'search/saved-search/rename', + getRoute: ({name, jsonQuery}: {name: string; jsonQuery: SearchQueryString}) => `search/saved-search/rename?name=${name}&q=${jsonQuery}` as const, + }, SEARCH_ADVANCED_FILTERS: 'search/filters', SEARCH_ADVANCED_FILTERS_DATE: 'search/filters/date', SEARCH_ADVANCED_FILTERS_CURRENCY: 'search/filters/currency', @@ -973,6 +977,18 @@ const ROUTES = { route: 'settings/workspaces/:policyID/company-cards/:feed/assign-card', getRoute: (policyID: string, feed: string) => `settings/workspaces/${policyID}/company-cards/${feed}/assign-card` as const, }, + WORKSPACE_COMPANY_CARD_DETAILS: { + route: 'settings/workspaces/:policyID/company-cards/:bank/:cardID', + getRoute: (policyID: string, cardID: string, bank: string, backTo?: string) => getUrlWithBackToParam(`settings/workspaces/${policyID}/company-cards/${bank}/${cardID}`, backTo), + }, + WORKSPACE_COMPANY_CARD_NAME: { + route: 'settings/workspaces/:policyID/company-cards/:bank/:cardID/edit/name', + getRoute: (policyID: string, cardID: string, bank: string) => `settings/workspaces/${policyID}/company-cards/${bank}/${cardID}/edit/name` as const, + }, + WORKSPACE_COMPANY_CARD_EXPORT: { + route: 'settings/workspaces/:policyID/company-cards/:bank/:cardID/edit/export', + getRoute: (policyID: string, cardID: string, bank: string) => `settings/workspaces/${policyID}/company-cards/${bank}/${cardID}/edit/export` as const, + }, WORKSPACE_EXPENSIFY_CARD_DETAILS: { route: 'settings/workspaces/:policyID/expensify-card/:cardID', getRoute: (policyID: string, cardID: string, backTo?: string) => getUrlWithBackToParam(`settings/workspaces/${policyID}/expensify-card/${cardID}`, backTo), diff --git a/src/SCREENS.ts b/src/SCREENS.ts index e8a3698e9a95..8168afba89ab 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -46,6 +46,7 @@ const SCREENS = { ADVANCED_FILTERS_TAG_RHP: 'Search_Advanced_Filters_Tag_RHP', ADVANCED_FILTERS_FROM_RHP: 'Search_Advanced_Filters_From_RHP', ADVANCED_FILTERS_TO_RHP: 'Search_Advanced_Filters_To_RHP', + SAVED_SEARCH_RENAME_RHP: 'Search_Saved_Search_Rename_RHP', ADVANCED_FILTERS_IN_RHP: 'Search_Advanced_Filters_In_RHP', TRANSACTION_HOLD_REASON_RHP: 'Search_Transaction_Hold_Reason_RHP', BOTTOM_TAB: 'Search_Bottom_Tab', @@ -172,6 +173,7 @@ const SCREENS = { TRAVEL: 'Travel', SEARCH_REPORT: 'SearchReport', SEARCH_ADVANCED_FILTERS: 'SearchAdvancedFilters', + SEARCH_SAVED_SEARCH: 'SearchSavedSearch', SETTINGS_CATEGORIES: 'SettingsCategories', RESTRICTED_ACTION: 'RestrictedAction', REPORT_EXPORT: 'Report_Export', @@ -384,6 +386,9 @@ const SCREENS = { COMPANY_CARDS_DETAILS: 'Workspace_CompanyCards_Details', COMPANY_CARDS_SETTINGS: 'Workspace_CompanyCards_Settings', COMPANY_CARDS_SETTINGS_FEED_NAME: 'Workspace_CompanyCards_Settings_Feed_Name', + COMPANY_CARD_DETAILS: 'Workspace_CompanyCard_Details', + COMPANY_CARD_NAME: 'Workspace_CompanyCard_Name', + COMPANY_CARD_EXPORT: 'Workspace_CompanyCard_Export', EXPENSIFY_CARD: 'Workspace_ExpensifyCard', EXPENSIFY_CARD_DETAILS: 'Workspace_ExpensifyCard_Details', EXPENSIFY_CARD_LIMIT: 'Workspace_ExpensifyCard_Limit', diff --git a/src/components/BaseMiniContextMenuItem.tsx b/src/components/BaseMiniContextMenuItem.tsx index 6e1a1e0fd229..fa0fdb45153f 100644 --- a/src/components/BaseMiniContextMenuItem.tsx +++ b/src/components/BaseMiniContextMenuItem.tsx @@ -79,7 +79,7 @@ function BaseMiniContextMenuItem( role={CONST.ROLE.BUTTON} style={({hovered, pressed}) => [ styles.reportActionContextMenuMiniButton, - StyleUtils.getButtonBackgroundColorStyle(getButtonState(hovered, pressed, isDelayButtonStateComplete)), + StyleUtils.getButtonBackgroundColorStyle(getButtonState(hovered, pressed, isDelayButtonStateComplete), true), isDelayButtonStateComplete && styles.cursorDefault, ]} > diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx index 9e67de51c47f..000445abb46d 100644 --- a/src/components/Button/index.tsx +++ b/src/components/Button/index.tsx @@ -80,6 +80,9 @@ type ButtonProps = Partial & { /** Additional styles to add after local styles. Applied to Pressable portion of button */ style?: StyleProp; + /** Additional styles to add to the component when it's disabled */ + disabledStyle?: StyleProp; + /** Additional button styles. Specific to the OpacityView of the button */ innerStyles?: StyleProp; @@ -140,13 +143,13 @@ type ButtonProps = Partial & { type KeyboardShortcutComponentProps = Pick; -const accessibilityRoles: string[] = Object.values(CONST.ACCESSIBILITY_ROLE); +const accessibilityRoles: string[] = Object.values(CONST.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 shouldDisableEnterShortcut = useMemo(() => accessibilityRoles.includes(activeElementRole ?? ''), [activeElementRole]); const keyboardShortcutCallback = useCallback( (event?: GestureResponderEvent | KeyboardEvent) => { @@ -206,6 +209,7 @@ function Button( enterKeyEventListenerPriority = 0, style = [], + disabledStyle, innerStyles = [], textStyles = [], textHoverStyles = [], @@ -381,6 +385,7 @@ function Button( danger && !isDisabled ? styles.buttonDangerHovered : undefined, hoverStyles, ]} + disabledStyle={disabledStyle} id={id} accessibilityLabel={accessibilityLabel} role={CONST.ROLE.BUTTON} diff --git a/src/components/ButtonWithDropdownMenu/index.tsx b/src/components/ButtonWithDropdownMenu/index.tsx index 1ff0eaae4726..c1b662c3680e 100644 --- a/src/components/ButtonWithDropdownMenu/index.tsx +++ b/src/components/ButtonWithDropdownMenu/index.tsx @@ -25,6 +25,7 @@ function ButtonWithDropdownMenu({ menuHeaderText = '', customText, style, + disabledStyle, buttonSize = CONST.DROPDOWN_BUTTON_SIZE.MEDIUM, anchorAlignment = { horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT, @@ -157,6 +158,7 @@ function ButtonWithDropdownMenu({ pressOnEnter={pressOnEnter} isDisabled={isDisabled || !!options[0].disabled} style={[styles.w100, style]} + disabledStyle={disabledStyle} isLoading={isLoading} text={selectedItem.text} onPress={(event) => onPress(event, options[0].value)} diff --git a/src/components/ButtonWithDropdownMenu/types.ts b/src/components/ButtonWithDropdownMenu/types.ts index 59bfd74cd55d..da6b3d93433d 100644 --- a/src/components/ButtonWithDropdownMenu/types.ts +++ b/src/components/ButtonWithDropdownMenu/types.ts @@ -68,6 +68,9 @@ type ButtonWithDropdownMenuProps = { /** Additional styles to add to the component */ style?: StyleProp; + /** Additional styles to add to the component when it's disabled */ + disabledStyle?: StyleProp; + /** Menu options to display */ /** e.g. [{text: 'Pay with Expensify', icon: Wallet}] */ options: Array>; diff --git a/src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts b/src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts index b472b80e5cbd..f6a4f5ba6e83 100644 --- a/src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts +++ b/src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts @@ -1,6 +1,6 @@ import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; -const BOTTOM_TAB_SCREENS = [SCREENS.HOME, SCREENS.SETTINGS.ROOT, NAVIGATORS.BOTTOM_TAB_NAVIGATOR]; +const BOTTOM_TAB_SCREENS = [SCREENS.HOME, SCREENS.SETTINGS.ROOT, NAVIGATORS.BOTTOM_TAB_NAVIGATOR, SCREENS.SEARCH.BOTTOM_TAB]; export default BOTTOM_TAB_SCREENS; diff --git a/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.tsx b/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.tsx index 97be05049e3c..d211aac7fd4c 100755 --- a/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.tsx +++ b/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.tsx @@ -82,8 +82,28 @@ function BaseHTMLEngineProvider({textSelectable = false, children, enableExperim mixedUAStyles: {...styles.textSupporting, ...styles.textLineThrough}, contentModel: HTMLContentModel.textual, }), + blockquote: HTMLElementModel.fromCustomModel({ + tagName: 'blockquote', + contentModel: HTMLContentModel.block, + getMixedUAStyles: (tnode) => { + if (tnode.attributes.isemojisonly === undefined) { + return; + } + return styles.onlyEmojisTextLineHeight; + }, + }), }), - [styles.formError, styles.mb0, styles.colorMuted, styles.textLabelSupporting, styles.lh16, styles.textSupporting, styles.textLineThrough, styles.mutedNormalTextLabel], + [ + styles.formError, + styles.mb0, + styles.colorMuted, + styles.textLabelSupporting, + styles.lh16, + styles.textSupporting, + styles.textLineThrough, + styles.mutedNormalTextLabel, + styles.onlyEmojisTextLineHeight, + ], ); /* eslint-enable @typescript-eslint/naming-convention */ diff --git a/src/components/Icon/Expensicons.ts b/src/components/Icon/Expensicons.ts index 698dc33b4a03..569e467dfad7 100644 --- a/src/components/Icon/Expensicons.ts +++ b/src/components/Icon/Expensicons.ts @@ -24,6 +24,7 @@ import Bell from '@assets/images/bell.svg'; import BellSlash from '@assets/images/bellSlash.svg'; import Bill from '@assets/images/bill.svg'; import Bolt from '@assets/images/bolt.svg'; +import Bookmark from '@assets/images/bookmark.svg'; import Box from '@assets/images/box.svg'; import Briefcase from '@assets/images/briefcase.svg'; import Bug from '@assets/images/bug.svg'; @@ -186,6 +187,7 @@ import Unlock from '@assets/images/unlock.svg'; import UploadAlt from '@assets/images/upload-alt.svg'; import Upload from '@assets/images/upload.svg'; import UserCheck from '@assets/images/user-check.svg'; +import UserEye from '@assets/images/user-eye.svg'; import UserPlus from '@assets/images/user-plus.svg'; import User from '@assets/images/user.svg'; import Users from '@assets/images/users.svg'; @@ -392,10 +394,12 @@ export { Filters, CalendarSolid, Filter, + UserEye, CaretUpDown, UserPlus, Feed, Table, SpreadsheetComputer, + Bookmark, Star, }; diff --git a/src/components/Icon/Illustrations.ts b/src/components/Icon/Illustrations.ts index 446137c3749b..954f9fa5caa7 100644 --- a/src/components/Icon/Illustrations.ts +++ b/src/components/Icon/Illustrations.ts @@ -1,5 +1,8 @@ import AmexCompanyCards from '@assets/images/companyCards/amex.svg'; import AmexBlueCompanyCards from '@assets/images/companyCards/card-amex-blue.svg'; +import AmexCardCompanyCardDetail from '@assets/images/companyCards/card-amex.svg'; +import MasterCardCompanyCardDetail from '@assets/images/companyCards/card-mastercard.svg'; +import VisaCompanyCardDetail from '@assets/images/companyCards/card-visa.svg'; import CompanyCardsEmptyState from '@assets/images/companyCards/emptystate__card-pos.svg'; import MasterCardCompanyCards from '@assets/images/companyCards/mastercard.svg'; import VisaCompanyCards from '@assets/images/companyCards/visa.svg'; @@ -237,5 +240,8 @@ export { MasterCardCompanyCards, VisaCompanyCards, AmexBlueCompanyCards, + VisaCompanyCardDetail, + MasterCardCompanyCardDetail, + AmexCardCompanyCardDetail, TurtleInShell, }; diff --git a/src/components/LHNOptionsList/OptionRowLHN.tsx b/src/components/LHNOptionsList/OptionRowLHN.tsx index 1686ed1c62d2..276e364e26c1 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.tsx +++ b/src/components/LHNOptionsList/OptionRowLHN.tsx @@ -221,7 +221,8 @@ function OptionRowLHN({reportID, isFocused = false, onSelectRow = () => {}, opti } }} withoutFocusOnSecondaryInteraction - activeOpacity={0.8} + activeOpacity={variables.pressDimValue} + opacityAnimationDuration={0} style={[ styles.flexRow, styles.alignItemsCenter, diff --git a/src/components/LinearGradient/index.native.ts b/src/components/LinearGradient/index.native.ts deleted file mode 100644 index 29af26b96b64..000000000000 --- a/src/components/LinearGradient/index.native.ts +++ /dev/null @@ -1,6 +0,0 @@ -import LinearGradientNative from 'react-native-linear-gradient'; -import type LinearGradient from './types'; - -const LinearGradientImplementation: LinearGradient = LinearGradientNative; - -export default LinearGradientImplementation; diff --git a/src/components/LinearGradient/index.ts b/src/components/LinearGradient/index.ts deleted file mode 100644 index 84d0fc2ce5c8..000000000000 --- a/src/components/LinearGradient/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import LinearGradientWeb from 'react-native-web-linear-gradient'; -import type LinearGradient from './types'; - -const LinearGradientImplementation: LinearGradient = LinearGradientWeb; - -export default LinearGradientImplementation; diff --git a/src/components/LinearGradient/types.ts b/src/components/LinearGradient/types.ts deleted file mode 100644 index 9e238ef71f12..000000000000 --- a/src/components/LinearGradient/types.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type LinearGradientNative from 'react-native-linear-gradient'; - -type LinearGradient = typeof LinearGradientNative; - -export default LinearGradient; diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx index d37bf32843d5..2524658d6ffc 100644 --- a/src/components/MenuItem.tsx +++ b/src/components/MenuItem.tsx @@ -3,7 +3,6 @@ import type {ReactElement, ReactNode} from 'react'; import React, {forwardRef, useContext, useMemo} from 'react'; import type {GestureResponderEvent, StyleProp, TextStyle, ViewStyle} from 'react-native'; import {ActivityIndicator, View} from 'react-native'; -import type {AnimatedStyle} from 'react-native-reanimated'; import type {ValueOf} from 'type-fest'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useStyleUtils from '@hooks/useStyleUtils'; @@ -91,9 +90,6 @@ type MenuItemBaseProps = { /** Any additional styles to apply to the label */ labelStyle?: StyleProp; - /** Any adjustments to style when menu item is hovered or pressed */ - hoverAndPressStyle?: StyleProp>; - /** Additional styles to style the description text below the title */ descriptionTextStyle?: StyleProp; @@ -348,7 +344,6 @@ function MenuItem( containerStyle, titleStyle, labelStyle, - hoverAndPressStyle, descriptionTextStyle, badgeStyle, viewMode = CONST.OPTION_MODE.DEFAULT, @@ -574,6 +569,8 @@ function MenuItem( onPressOut={ControlSelection.unblock} onSecondaryInteraction={onSecondaryInteraction} wrapperStyle={outerWrapperStyle} + activeOpacity={variables.pressDimValue} + opacityAnimationDuration={0} style={({pressed}) => [ containerStyle, @@ -582,7 +579,6 @@ function MenuItem( !shouldRemoveBackground && StyleUtils.getButtonBackgroundColorStyle(getButtonState(focused || isHovered, pressed, success, disabled, interactive), true), ...(Array.isArray(wrapperStyle) ? wrapperStyle : [wrapperStyle]), - !focused && (isHovered || pressed) && hoverAndPressStyle, shouldGreyOutWhenDisabled && disabled && styles.buttonOpacityDisabled, isHovered && interactive && !focused && !pressed && !shouldRemoveBackground && styles.hoveredComponentBG, ] as StyleProp diff --git a/src/components/MenuItemList.tsx b/src/components/MenuItemList.tsx index 623198498dd1..2e732c691140 100644 --- a/src/components/MenuItemList.tsx +++ b/src/components/MenuItemList.tsx @@ -1,9 +1,10 @@ import React, {useRef} from 'react'; -import type {GestureResponderEvent, View} from 'react-native'; +import type {GestureResponderEvent, StyleProp, View, ViewStyle} from 'react-native'; import useSingleExecution from '@hooks/useSingleExecution'; import * as ReportActionContextMenu from '@pages/home/report/ContextMenu/ReportActionContextMenu'; import CONST from '@src/CONST'; import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; +import type IconAsset from '@src/types/utils/IconAsset'; import type {MenuItemProps} from './MenuItem'; import MenuItem from './MenuItem'; import OfflineWithFeedback from './OfflineWithFeedback'; @@ -36,9 +37,32 @@ type MenuItemListProps = { /** Whether or not to use the single execution hook */ shouldUseSingleExecution?: boolean; + + /** Any additional styles to apply for each item */ + wrapperStyle?: StyleProp; + + /** Icon to display on the left side of each item */ + icon?: IconAsset; + + /** Icon Width */ + iconWidth?: number; + + /** Icon Height */ + iconHeight?: number; + + /** Is this in the Pane */ + isPaneMenu?: boolean; }; -function MenuItemList({menuItems = [], shouldUseSingleExecution = false}: MenuItemListProps) { +function MenuItemList({ + menuItems = [], + shouldUseSingleExecution = false, + wrapperStyle = {}, + icon = undefined, + iconWidth = undefined, + iconHeight = undefined, + isPaneMenu = false, +}: MenuItemListProps) { const popoverAnchor = useRef(null); const {isExecuting, singleExecution} = useSingleExecution(); @@ -67,9 +91,14 @@ function MenuItemList({menuItems = [], shouldUseSingleExecution = false}: MenuIt > secondaryInteraction(menuItemProps.link, e) : undefined} ref={popoverAnchor} shouldBlockSelection={!!menuItemProps.link} + icon={icon} + iconWidth={iconWidth} + iconHeight={iconHeight} + isPaneMenu={isPaneMenu} // eslint-disable-next-line react/jsx-props-no-spreading {...menuItemProps} disabled={!!menuItemProps.disabled || isExecuting} diff --git a/src/components/OpacityView.tsx b/src/components/OpacityView.tsx index d4a5c05167a0..f4884fd3c0f8 100644 --- a/src/components/OpacityView.tsx +++ b/src/components/OpacityView.tsx @@ -24,11 +24,24 @@ type OpacityViewProps = { */ dimmingValue?: number; + /** + * The duration of the dimming animation + * @default variables.dimAnimationDuration + */ + dimAnimationDuration?: number; + /** Whether the view needs to be rendered offscreen (for Android only) */ needsOffscreenAlphaCompositing?: boolean; }; -function OpacityView({shouldDim, children, style = [], dimmingValue = variables.hoverDimValue, needsOffscreenAlphaCompositing = false}: OpacityViewProps) { +function OpacityView({ + shouldDim, + dimAnimationDuration = variables.dimAnimationDuration, + children, + style = [], + dimmingValue = variables.hoverDimValue, + needsOffscreenAlphaCompositing = false, +}: OpacityViewProps) { const opacity = useSharedValue(1); const opacityStyle = useAnimatedStyle(() => ({ opacity: opacity.value, @@ -37,11 +50,11 @@ function OpacityView({shouldDim, children, style = [], dimmingValue = variables. React.useEffect(() => { if (shouldDim) { // eslint-disable-next-line react-compiler/react-compiler - opacity.value = withTiming(dimmingValue, {duration: 50}); + opacity.value = withTiming(dimmingValue, {duration: dimAnimationDuration}); } else { - opacity.value = withTiming(1, {duration: 50}); + opacity.value = withTiming(1, {duration: dimAnimationDuration}); } - }, [shouldDim, dimmingValue, opacity]); + }, [shouldDim, dimmingValue, opacity, dimAnimationDuration]); return ( ; @@ -130,6 +136,7 @@ function PopoverMenu({ const [currentMenuItems, setCurrentMenuItems] = useState(menuItems); const currentMenuItemsFocusedIndex = currentMenuItems?.findIndex((option) => option.isSelected); const [enteredSubMenuIndexes, setEnteredSubMenuIndexes] = useState(CONST.EMPTY_ARRAY); + const {windowHeight} = useWindowDimensions(); const [focusedIndex, setFocusedIndex] = useArrowKeyFocusManager({initialFocusedIndex: currentMenuItemsFocusedIndex, maxIndex: currentMenuItems.length - 1, isActive: isVisible}); @@ -142,9 +149,13 @@ function PopoverMenu({ setFocusedIndex(selectedSubMenuItemIndex); } else if (selectedItem.shouldCallAfterModalHide && !Browser.isSafari()) { onItemSelected(selectedItem, index); - Modal.close(() => { - selectedItem.onSelected?.(); - }); + Modal.close( + () => { + selectedItem.onSelected?.(); + }, + undefined, + selectedItem.shouldCloseAllModals, + ); } else { onItemSelected(selectedItem, index); selectedItem.onSelected?.(); @@ -247,7 +258,7 @@ function PopoverMenu({ restoreFocusType={restoreFocusType} > - + {renderHeaderText()} {enteredSubMenuIndexes.length > 0 && renderBackButtonItem()} {currentMenuItems.map((item, menuIndex) => ( @@ -269,7 +280,9 @@ function PopoverMenu({ focused={focusedIndex === menuIndex} displayInDefaultIconColor={item.displayInDefaultIconColor} shouldShowRightIcon={item.shouldShowRightIcon} + shouldShowRightComponent={item.shouldShowRightComponent} iconRight={item.iconRight} + rightComponent={item.rightComponent} shouldPutLeftPaddingWhenNoIcon={item.shouldPutLeftPaddingWhenNoIcon} label={item.label} style={{backgroundColor: item.isSelected ? theme.activeComponentBG : undefined}} @@ -293,7 +306,7 @@ function PopoverMenu({ badgeText={item.badgeText} /> ))} - + ); diff --git a/src/components/Pressable/PressableWithFeedback.tsx b/src/components/Pressable/PressableWithFeedback.tsx index d50404873eeb..10e6ac7bbca6 100644 --- a/src/components/Pressable/PressableWithFeedback.tsx +++ b/src/components/Pressable/PressableWithFeedback.tsx @@ -26,6 +26,12 @@ type PressableWithFeedbackProps = PressableProps & { */ hoverDimmingValue?: number; + /** + * The duration of the dimming animation + * @default variables.dimAnimationDuration + */ + dimAnimationDuration?: number; + /** Whether the view needs to be rendered offscreen (for Android only) */ needsOffscreenAlphaCompositing?: boolean; @@ -40,6 +46,7 @@ function PressableWithFeedback( needsOffscreenAlphaCompositing = false, pressDimmingValue = variables.pressDimValue, hoverDimmingValue = variables.hoverDimValue, + dimAnimationDuration, ...rest }: PressableWithFeedbackProps, ref: PressableRef, @@ -51,6 +58,7 @@ function PressableWithFeedback( diff --git a/src/components/PressableWithSecondaryInteraction/index.tsx b/src/components/PressableWithSecondaryInteraction/index.tsx index cbcf8523d9a4..810aa45ebf07 100644 --- a/src/components/PressableWithSecondaryInteraction/index.tsx +++ b/src/components/PressableWithSecondaryInteraction/index.tsx @@ -20,6 +20,7 @@ function PressableWithSecondaryInteraction( preventDefaultContextMenu = true, onSecondaryInteraction, activeOpacity = 1, + opacityAnimationDuration, ...rest }: PressableWithSecondaryInteractionProps, ref: PressableRef, @@ -100,6 +101,7 @@ function PressableWithSecondaryInteraction( wrapperStyle={[StyleUtils.combineStyles(DeviceCapabilities.canUseTouchScreen() ? [styles.userSelectNone, styles.noSelect] : [], inlineStyle), wrapperStyle]} onLongPress={onSecondaryInteraction ? executeSecondaryInteraction : undefined} pressDimmingValue={activeOpacity} + dimAnimationDuration={opacityAnimationDuration} ref={pressableRef} style={(state) => [StyleUtils.parseStyleFromFunction(style, state), inlineStyle]} needsOffscreenAlphaCompositing={needsOffscreenAlphaCompositing} diff --git a/src/components/PressableWithSecondaryInteraction/types.ts b/src/components/PressableWithSecondaryInteraction/types.ts index b07c867daeb3..ebe08cfab4f2 100644 --- a/src/components/PressableWithSecondaryInteraction/types.ts +++ b/src/components/PressableWithSecondaryInteraction/types.ts @@ -40,6 +40,12 @@ type PressableWithSecondaryInteractionProps = PressableWithFeedbackProps & { /** Opacity to reduce to when active */ activeOpacity?: number; + /** + * The duration of the opacity animation + * @default variables.dimAnimationDuration + */ + opacityAnimationDuration?: number; + /** Used to apply styles to the Pressable */ style?: ParsableStyle; diff --git a/src/components/ReportActionItem/IssueCardMessage.tsx b/src/components/ReportActionItem/IssueCardMessage.tsx index 16015311738f..d12a20c4598d 100644 --- a/src/components/ReportActionItem/IssueCardMessage.tsx +++ b/src/components/ReportActionItem/IssueCardMessage.tsx @@ -3,15 +3,15 @@ import type {OnyxEntry} from 'react-native-onyx'; import {useOnyx} from 'react-native-onyx'; import Button from '@components/Button'; import RenderHTML from '@components/RenderHTML'; -import useEnvironment from '@hooks/useEnvironment'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; +import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {ReportAction} from '@src/types/onyx'; -import type OriginalMessage from '@src/types/onyx/OriginalMessage'; +import type {IssueNewCardOriginalMessage} from '@src/types/onyx/OriginalMessage'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; type IssueCardMessageProps = { @@ -20,22 +20,14 @@ type IssueCardMessageProps = { policyID: string | undefined; }; -type IssueNewCardOriginalMessage = OriginalMessage< - typeof CONST.REPORT.ACTIONS.TYPE.CARD_MISSING_ADDRESS | typeof CONST.REPORT.ACTIONS.TYPE.CARD_ISSUED | typeof CONST.REPORT.ACTIONS.TYPE.CARD_ISSUED_VIRTUAL ->; - function IssueCardMessage({action, policyID}: IssueCardMessageProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); - const {environmentURL} = useEnvironment(); const [privatePersonalDetails] = useOnyx(ONYXKEYS.PRIVATE_PERSONAL_DETAILS); const [session] = useOnyx(ONYXKEYS.SESSION); const assigneeAccountID = (action?.originalMessage as IssueNewCardOriginalMessage)?.assigneeAccountID; - const assignee = ``; - const link = `${translate('cardPage.expensifyCard')}`; - const missingDetails = !privatePersonalDetails?.legalFirstName || !privatePersonalDetails?.legalLastName || @@ -46,25 +38,12 @@ function IssueCardMessage({action, policyID}: IssueCardMessageProps) { const isAssigneeCurrentUser = !isEmptyObject(session) && session.accountID === assigneeAccountID; - const shouldShowDetailsButton = action?.actionName === CONST.REPORT.ACTIONS.TYPE.CARD_MISSING_ADDRESS && missingDetails && isAssigneeCurrentUser; - - const getTranslation = () => { - switch (action?.actionName) { - case CONST.REPORT.ACTIONS.TYPE.CARD_ISSUED: - return translate('workspace.expensifyCard.issuedCard', assignee); - case CONST.REPORT.ACTIONS.TYPE.CARD_ISSUED_VIRTUAL: - return translate('workspace.expensifyCard.issuedCardVirtual', {assignee, link}); - case CONST.REPORT.ACTIONS.TYPE.CARD_MISSING_ADDRESS: - return translate(`workspace.expensifyCard.${!isAssigneeCurrentUser || shouldShowDetailsButton ? 'issuedCardNoShippingDetails' : 'addedShippingDetails'}`, assignee); - default: - return ''; - } - }; + const shouldShowAddMissingDetailsButton = action?.actionName === CONST.REPORT.ACTIONS.TYPE.CARD_MISSING_ADDRESS && missingDetails && isAssigneeCurrentUser; return ( <> - ${getTranslation()}`} /> - {shouldShowDetailsButton && ( + ${ReportActionsUtils.getCardIssuedMessage(action, true)}`} /> + {shouldShowAddMissingDetailsButton && (