diff --git a/Gemfile.lock b/Gemfile.lock index 93dab195ebdd..fcf4f878e2de 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -81,7 +81,8 @@ GEM declarative (0.0.20) digest-crc (0.6.5) rake (>= 12.0.0, < 14.0.0) - domain_name (0.6.20231109) + domain_name (0.5.20190701) + unf (>= 0.0.5, < 1.0.0) dotenv (2.8.1) emoji_regex (3.2.3) escape (0.0.4) @@ -261,6 +262,9 @@ GEM tzinfo (2.0.6) concurrent-ruby (~> 1.0) uber (0.1.0) + unf (0.1.4) + unf_ext + unf_ext (0.0.9.1) unicode-display_width (2.5.0) webrick (1.8.1) word_wrap (1.0.0) @@ -294,4 +298,4 @@ RUBY VERSION ruby 2.6.10p210 BUNDLED WITH - 2.1.4 + 2.4.7 diff --git a/__mocks__/@ua/react-native-airship.js b/__mocks__/@ua/react-native-airship.js index 29be662e96a1..65e7c1a8b97e 100644 --- a/__mocks__/@ua/react-native-airship.js +++ b/__mocks__/@ua/react-native-airship.js @@ -28,6 +28,7 @@ const Airship = { enableUserNotifications: () => Promise.resolve(false), clearNotifications: jest.fn(), getNotificationStatus: () => Promise.resolve({airshipOptIn: false, systemEnabled: false}), + getActiveNotifications: () => Promise.resolve([]), }, contact: { identify: jest.fn(), diff --git a/android/app/build.gradle b/android/app/build.gradle index 00ba8df0ad97..6ad9e7f28407 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -91,8 +91,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001041303 - versionName "1.4.13-3" + versionCode 1001041306 + versionName "1.4.13-6" } flavorDimensions "default" diff --git a/assets/animations/Fireworks.lottie b/assets/animations/Fireworks.lottie index f5a782c62f3a..142efdcd8fdc 100644 Binary files a/assets/animations/Fireworks.lottie and b/assets/animations/Fireworks.lottie differ diff --git a/assets/animations/ReviewingBankInfo.lottie b/assets/animations/ReviewingBankInfo.lottie index 93addc052e8b..a9974366cae7 100644 Binary files a/assets/animations/ReviewingBankInfo.lottie and b/assets/animations/ReviewingBankInfo.lottie differ diff --git a/docs/articles/expensify-classic/workspace-and-domain-settings/Budgets.md b/docs/articles/expensify-classic/workspace-and-domain-settings/Budgets.md new file mode 100644 index 000000000000..3c5bc0fe2421 --- /dev/null +++ b/docs/articles/expensify-classic/workspace-and-domain-settings/Budgets.md @@ -0,0 +1,56 @@ +--- +title: Budgets +description: Track employee spending across categories and tags by using Expensify's Budgets feature. +--- + +# About +Expensify’s Budgets feature allows you to: +- Set monthly and yearly budgets +- Track spending across categories and tags on an individual and workspace basis +- Get notified when a budget has met specific thresholds + +# How-to +## Category Budgets +1. Navigate to **Settings > Group > [Workspace Name] > Categories** +2. Click the **Edit Rules** button for the category you want to add a budget to +3. Select the **Budget** tab at the top of the modal that opens +4. Click the switch next to **Enable Budget** +5. Once enabled, you will see additional settings to configure: + - **Budget frequency**: you can select if you want this to be a monthly or a yearly budget + - **Total workspace budget**: you can enter an amount if you want to set a budget for the entire workspace + - **Per individual budget**: you can enter an amount if you want to set a budget per person + - **Notification threshold** - this is the % in which you will be notified as the budgets are hit + +## Single-level Tag Budgets +1. Navigate to **Settings > Group > [Workspace Name] > Tags** +2. Click **Edit Budget** next to the tag you want to add a budget to +3. Click the switch next to **Enable Budget** +4. Once enabled, you will see additional settings to configure: + - **Budget frequency**: you can select if you want this to be a monthly or a yearly budget + - **Total workspace budget**: you can enter an amount if you want to set a budget for the entire workspace + - **Per individual budget**: you can enter an amount if you want to set a budget per person + - **Notification threshold** - this is the % in which you will be notified as the budgets are hit + +## Multi-level Tag Budgets +1. Navigate to **Settings > Group > [Workspace Name] > Tags** +2. Click the **Edit Tags** button +3. Click the **Edit Budget** button next to the subtag you want to apply a budget to +4. Click the switch next to **Enable Budget** +5. Once enabled, you will see additional settings to configure: + - **Budget frequency**: you can select if you want this to be a monthly or a yearly budget + - **Total workspace budget**: you can enter an amount if you want to set a budget for the entire workspace + - **Per individual budget**: you can enter an amount if you want to set a budget per person + - **Notification threshold** - this is the % in which you will be notified as the budgets are hit + +# FAQ +## Can I import budgets as a CSV? +At this time, you cannot import budgets via CSV since we don’t import categories or tags from direct accounting integrations. + +## When will I be notified as a budget is hit? +Notifications are sent twice: + - When your notification threshold is hit (i.e, if you set this as 50%, you’ll be notified when 50% of the budget is met) + - When 100% of the budget is met + +## How will I be notified when a budget is hit? +A message will be sent in the #admins room of the Workspace. + diff --git a/docs/articles/new-expensify/get-paid-back/Referral-Program.md b/docs/articles/new-expensify/get-paid-back/Referral-Program.md index 34a35f5dc7c8..6ffb923aeb76 100644 --- a/docs/articles/new-expensify/get-paid-back/Referral-Program.md +++ b/docs/articles/new-expensify/get-paid-back/Referral-Program.md @@ -12,13 +12,16 @@ As a thank you, every time you bring a new customer into New Expensify, you'll g # How to get paid to refer anyone to New Expensify -The sky's the limit for this referral program! Your referral can be anyone - a friend, family member, boss, coworker, neighbor, or even social media follower. We're making it as easy as possible to get that cold hard referral $$$. +The sky's the limit for this referral program! Your referral can be anyone - a friend, family member, boss, coworker, neighbor, or even social media follower. We're making it as easy as possible to get that cold hard $$$. -1. There are a bunch of different ways to kick off a referral in New Expensify: +1. There are a bunch of different ways to refer someone to New Expensify: - Start a chat - Request money - Send money - - @ mention someone + - Split a bill + - Assign them a task + - @ mention them + - Invite them to a room - Add them to a workspace 2. You'll get $250 for each referral as long as: diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index d93eeff2d49d..8989d0ef3542 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.13.3 + 1.4.13.6 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index fd6edef4c713..95659bf6908d 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.4.13.3 + 1.4.13.6 diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 390511397b0e..eebd6ad532d4 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,25 +1,25 @@ PODS: - - Airship (16.11.3): - - Airship/Automation (= 16.11.3) - - Airship/Basement (= 16.11.3) - - Airship/Core (= 16.11.3) - - Airship/ExtendedActions (= 16.11.3) - - Airship/MessageCenter (= 16.11.3) - - Airship/Automation (16.11.3): + - Airship (16.12.1): + - Airship/Automation (= 16.12.1) + - Airship/Basement (= 16.12.1) + - Airship/Core (= 16.12.1) + - Airship/ExtendedActions (= 16.12.1) + - Airship/MessageCenter (= 16.12.1) + - Airship/Automation (16.12.1): - Airship/Core - - Airship/Basement (16.11.3) - - Airship/Core (16.11.3): + - Airship/Basement (16.12.1) + - Airship/Core (16.12.1): - Airship/Basement - - Airship/ExtendedActions (16.11.3): + - Airship/ExtendedActions (16.12.1): - Airship/Core - - Airship/MessageCenter (16.11.3): + - Airship/MessageCenter (16.12.1): - Airship/Core - - Airship/PreferenceCenter (16.11.3): + - Airship/PreferenceCenter (16.12.1): - Airship/Core - - AirshipFrameworkProxy (2.0.8): - - Airship (= 16.11.3) - - Airship/MessageCenter (= 16.11.3) - - Airship/PreferenceCenter (= 16.11.3) + - AirshipFrameworkProxy (2.1.1): + - Airship (= 16.12.1) + - Airship/MessageCenter (= 16.12.1) + - Airship/PreferenceCenter (= 16.12.1) - AppAuth (1.6.2): - AppAuth/Core (= 1.6.2) - AppAuth/ExternalUserAgent (= 1.6.2) @@ -558,8 +558,8 @@ PODS: - React-jsinspector (0.72.4) - React-logger (0.72.4): - glog - - react-native-airship (15.2.6): - - AirshipFrameworkProxy (= 2.0.8) + - react-native-airship (15.3.1): + - AirshipFrameworkProxy (= 2.1.1) - React-Core - react-native-blob-util (0.17.3): - React-Core @@ -777,35 +777,10 @@ PODS: - React-Core - RNReactNativeHapticFeedback (1.14.0): - React-Core - - RNReanimated (3.5.4): - - DoubleConversion - - FBLazyVector - - glog - - hermes-engine - - RCT-Folly - - RCTRequired - - RCTTypeSafety - - React-callinvoker + - RNReanimated (3.6.1): + - RCT-Folly (= 2021.07.22.00) - React-Core - - React-Core/DevSupport - - React-Core/RCTWebSocket - - React-CoreModules - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-jsinspector - - React-RCTActionSheet - - React-RCTAnimation - - React-RCTAppDelegate - - React-RCTBlob - - React-RCTImage - - React-RCTLinking - - React-RCTNetwork - - React-RCTSettings - - React-RCTText - ReactCommon/turbomodule/core - - Yoga - RNScreens (3.21.0): - React-Core - React-RCTImage @@ -1160,8 +1135,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/yoga" SPEC CHECKSUMS: - Airship: c70eed50e429f97f5adb285423c7291fb7a032ae - AirshipFrameworkProxy: 7bc4130c668c6c98e2d4c60fe4c9eb61a999be99 + Airship: 2f4510b497a8200780752a5e0304a9072bfffb6d + AirshipFrameworkProxy: ea1b6c665c798637b93c465b5e505be3011f1d9d AppAuth: 3bb1d1cd9340bd09f5ed189fb00b1cc28e1e8570 boost: 57d2868c099736d80fcd648bf211b4431e51a558 BVLinearGradient: 421743791a59d259aec53f4c58793aad031da2ca @@ -1224,7 +1199,7 @@ SPEC CHECKSUMS: React-jsiexecutor: c7f826e40fa9cab5d37cab6130b1af237332b594 React-jsinspector: aaed4cf551c4a1c98092436518c2d267b13a673f React-logger: da1ebe05ae06eb6db4b162202faeafac4b435e77 - react-native-airship: 5d19f4ba303481cf4101ff9dee9249ef6a8a6b64 + react-native-airship: 6ded22e4ca54f2f80db80b7b911c2b9b696d9335 react-native-blob-util: 99f4d79189252f597fe0d810c57a3733b1b1dea6 react-native-cameraroll: 8ffb0af7a5e5de225fd667610e2979fc1f0c2151 react-native-config: 7cd105e71d903104e8919261480858940a6b9c0e @@ -1280,7 +1255,7 @@ SPEC CHECKSUMS: rnmapbox-maps: 6f638ec002aa6e906a6f766d69cd45f968d98e64 RNPermissions: 9b086c8f05b2e2faa587fdc31f4c5ab4509728aa RNReactNativeHapticFeedback: 1e3efeca9628ff9876ee7cdd9edec1b336913f8c - RNReanimated: ab2e96c6d5591c3dfbb38a464f54c8d17fb34a87 + RNReanimated: fdbaa9c964bbab7fac50c90862b6cc5f041679b9 RNScreens: d037903436160a4b039d32606668350d2a808806 RNSVG: d00c8f91c3cbf6d476451313a18f04d220d4f396 SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d diff --git a/package-lock.json b/package-lock.json index 03fafb4bda7d..5206b9bf8618 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.13-3", + "version": "1.4.13-6", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.13-3", + "version": "1.4.13-6", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -41,7 +41,7 @@ "@rnmapbox/maps": "^10.0.11", "@shopify/flash-list": "^1.6.1", "@types/node": "^18.14.0", - "@ua/react-native-airship": "^15.2.6", + "@ua/react-native-airship": "^15.3.1", "awesome-phonenumber": "^5.4.0", "babel-polyfill": "^6.26.0", "canvas-size": "^1.2.6", @@ -100,7 +100,7 @@ "react-native-plaid-link-sdk": "10.8.0", "react-native-qrcode-svg": "^6.2.0", "react-native-quick-sqlite": "^8.0.0-beta.2", - "react-native-reanimated": "3.5.4", + "react-native-reanimated": "^3.6.1", "react-native-render-html": "6.3.1", "react-native-safe-area-context": "4.4.1", "react-native-screens": "3.21.0", @@ -20437,9 +20437,9 @@ } }, "node_modules/@ua/react-native-airship": { - "version": "15.2.6", - "resolved": "https://registry.npmjs.org/@ua/react-native-airship/-/react-native-airship-15.2.6.tgz", - "integrity": "sha512-dVlBPPYXD/4SEshv/X7mmt3xF8WfnNqiSNzCyqJSLAZ1aJuPpP9Z5WemCYsa2iv6goRZvtJSE4P79QKlfoTwXw==", + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/@ua/react-native-airship/-/react-native-airship-15.3.1.tgz", + "integrity": "sha512-g5YX4/fpBJ0ml//7ave8HE68uF4QFriCuei0xJwK+ClzbTDWYB6OldvE/wj5dMpgQ95ZFSbr5LU77muYScxXLQ==", "engines": { "node": ">= 16.0.0" }, @@ -44561,9 +44561,9 @@ } }, "node_modules/react-native-reanimated": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.4.tgz", - "integrity": "sha512-8we9LLDO1o4Oj9/DICeEJ2K1tjfqkJagqQUglxeUAkol/HcEJ6PGxIrpBcNryLqCDYEcu6FZWld/FzizBIw6bg==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.6.1.tgz", + "integrity": "sha512-F4vG9Yf9PKmE3GaWtVGUpzj3SM6YY2cx1yRHCwiMd1uY7W0gU017LfcVUorboJnj0y5QZqEriEK1Usq2Y8YZqg==", "dependencies": { "@babel/plugin-transform-object-assign": "^7.16.7", "@babel/preset-typescript": "^7.16.7", @@ -67439,9 +67439,9 @@ } }, "@ua/react-native-airship": { - "version": "15.2.6", - "resolved": "https://registry.npmjs.org/@ua/react-native-airship/-/react-native-airship-15.2.6.tgz", - "integrity": "sha512-dVlBPPYXD/4SEshv/X7mmt3xF8WfnNqiSNzCyqJSLAZ1aJuPpP9Z5WemCYsa2iv6goRZvtJSE4P79QKlfoTwXw==", + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/@ua/react-native-airship/-/react-native-airship-15.3.1.tgz", + "integrity": "sha512-g5YX4/fpBJ0ml//7ave8HE68uF4QFriCuei0xJwK+ClzbTDWYB6OldvE/wj5dMpgQ95ZFSbr5LU77muYScxXLQ==", "requires": {} }, "@vercel/ncc": { @@ -84883,9 +84883,9 @@ "requires": {} }, "react-native-reanimated": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.4.tgz", - "integrity": "sha512-8we9LLDO1o4Oj9/DICeEJ2K1tjfqkJagqQUglxeUAkol/HcEJ6PGxIrpBcNryLqCDYEcu6FZWld/FzizBIw6bg==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.6.1.tgz", + "integrity": "sha512-F4vG9Yf9PKmE3GaWtVGUpzj3SM6YY2cx1yRHCwiMd1uY7W0gU017LfcVUorboJnj0y5QZqEriEK1Usq2Y8YZqg==", "requires": { "@babel/plugin-transform-object-assign": "^7.16.7", "@babel/preset-typescript": "^7.16.7", diff --git a/package.json b/package.json index 9a7d298709d4..8432a773fdf7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.13-3", + "version": "1.4.13-6", "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.", @@ -89,7 +89,7 @@ "@rnmapbox/maps": "^10.0.11", "@shopify/flash-list": "^1.6.1", "@types/node": "^18.14.0", - "@ua/react-native-airship": "^15.2.6", + "@ua/react-native-airship": "^15.3.1", "awesome-phonenumber": "^5.4.0", "babel-polyfill": "^6.26.0", "canvas-size": "^1.2.6", @@ -148,7 +148,7 @@ "react-native-plaid-link-sdk": "10.8.0", "react-native-qrcode-svg": "^6.2.0", "react-native-quick-sqlite": "^8.0.0-beta.2", - "react-native-reanimated": "3.5.4", + "react-native-reanimated": "^3.6.1", "react-native-render-html": "6.3.1", "react-native-safe-area-context": "4.4.1", "react-native-screens": "3.21.0", diff --git a/patches/react-native-fast-image+8.6.3.patch b/patches/react-native-fast-image+8.6.3+001+initial.patch similarity index 100% rename from patches/react-native-fast-image+8.6.3.patch rename to patches/react-native-fast-image+8.6.3+001+initial.patch diff --git a/patches/react-native-fast-image+8.6.3+002+bitmap-downsampling.patch b/patches/react-native-fast-image+8.6.3+002+bitmap-downsampling.patch new file mode 100644 index 000000000000..a626d5b16b2f --- /dev/null +++ b/patches/react-native-fast-image+8.6.3+002+bitmap-downsampling.patch @@ -0,0 +1,62 @@ +diff --git a/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/FastImageViewWithUrl.java b/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/FastImageViewWithUrl.java +index 1339f5c..9dfec0c 100644 +--- a/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/FastImageViewWithUrl.java ++++ b/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/FastImageViewWithUrl.java +@@ -176,7 +176,8 @@ class FastImageViewWithUrl extends AppCompatImageView { + .apply(FastImageViewConverter + .getOptions(context, imageSource, mSource) + .placeholder(mDefaultSource) // show until loaded +- .fallback(mDefaultSource)); // null will not be treated as error ++ .fallback(mDefaultSource)) ++ .transform(new ResizeTransformation()); + + if (key != null) + builder.listener(new FastImageRequestListener(key)); +diff --git a/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/ResizeTransformation.java b/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/ResizeTransformation.java +new file mode 100644 +index 0000000..1daa227 +--- /dev/null ++++ b/node_modules/react-native-fast-image/android/src/main/java/com/dylanvann/fastimage/ResizeTransformation.java +@@ -0,0 +1,41 @@ ++package com.dylanvann.fastimage; ++ ++ import android.content.Context; ++ import android.graphics.Bitmap; ++ ++ import androidx.annotation.NonNull; ++ ++ import com.bumptech.glide.load.Transformation; ++ import com.bumptech.glide.load.engine.Resource; ++ import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; ++ import com.bumptech.glide.load.resource.bitmap.BitmapResource; ++ ++ import java.security.MessageDigest; ++ ++ public class ResizeTransformation implements Transformation { ++ ++ private final double MAX_BYTES = 25000000.0; ++ ++ @NonNull ++ @Override ++ public Resource transform(@NonNull Context context, @NonNull Resource resource, int outWidth, int outHeight) { ++ Bitmap toTransform = resource.get(); ++ ++ if (toTransform.getByteCount() > MAX_BYTES) { ++ double scaleFactor = Math.sqrt(MAX_BYTES / (double) toTransform.getByteCount()); ++ int newHeight = (int) (outHeight * scaleFactor); ++ int newWidth = (int) (outWidth * scaleFactor); ++ ++ BitmapPool pool = GlideApp.get(context).getBitmapPool(); ++ Bitmap scaledBitmap = Bitmap.createScaledBitmap(toTransform, newWidth, newHeight, true); ++ return BitmapResource.obtain(scaledBitmap, pool); ++ } ++ ++ return resource; ++ } ++ ++ @Override ++ public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) { ++ messageDigest.update(("ResizeTransformation").getBytes()); ++ } ++ } +\ No newline at end of file diff --git a/src/CONST.ts b/src/CONST.ts index 2733da56e597..219807587a25 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -464,6 +464,7 @@ const CONST = { ONFIDO_TERMS_OF_SERVICE_URL: 'https://onfido.com/terms-of-service/', // Use Environment.getEnvironmentURL to get the complete URL with port number DEV_NEW_EXPENSIFY_URL: 'https://dev.new.expensify.com:', + EXPENSIFY_INBOX_URL: 'https://www.expensify.com/inbox', SIGN_IN_FORM_WIDTH: 300, diff --git a/src/components/AttachmentModal.js b/src/components/AttachmentModal.js index 13b3b9f1e836..b1af96561ef5 100755 --- a/src/components/AttachmentModal.js +++ b/src/components/AttachmentModal.js @@ -4,6 +4,7 @@ import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {Animated, Keyboard, View} from 'react-native'; +import {GestureHandlerRootView} from 'react-native-gesture-handler'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; import useLocalize from '@hooks/useLocalize'; @@ -425,78 +426,80 @@ function AttachmentModal(props) { }} propagateSwipe > - {props.isSmallScreenWidth && } - downloadAttachment(source)} - shouldShowCloseButton={!props.isSmallScreenWidth} - shouldShowBackButton={props.isSmallScreenWidth} - onBackButtonPress={closeModal} - onCloseButtonPress={closeModal} - shouldShowThreeDotsButton={shouldShowThreeDotsButton} - threeDotsAnchorPosition={styles.threeDotsPopoverOffsetAttachmentModal(windowWidth)} - threeDotsMenuItems={threeDotsMenuItems} - shouldOverlay - /> - - {!_.isEmpty(props.report) && !props.isReceiptAttachment ? ( - - ) : ( - Boolean(sourceForAttachmentView) && - shouldLoadAttachment && ( - + {props.isSmallScreenWidth && } + downloadAttachment(source)} + shouldShowCloseButton={!props.isSmallScreenWidth} + shouldShowBackButton={props.isSmallScreenWidth} + onBackButtonPress={closeModal} + onCloseButtonPress={closeModal} + shouldShowThreeDotsButton={shouldShowThreeDotsButton} + threeDotsAnchorPosition={styles.threeDotsPopoverOffsetAttachmentModal(windowWidth)} + threeDotsMenuItems={threeDotsMenuItems} + shouldOverlay + /> + + {!_.isEmpty(props.report) && !props.isReceiptAttachment ? ( + - ) - )} - - {/* If we have an onConfirm method show a confirmation button */} - {Boolean(props.onConfirm) && ( - - {({safeAreaPaddingBottomStyle}) => ( - -