diff --git a/ios/Podfile.lock b/ios/Podfile.lock index ca2aba9b49f8..80f75b7712b9 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -465,8 +465,8 @@ PODS: - DoubleConversion - FBLazyVector - FBReactNativeSpec - - Folly - glog + - RCT-Folly - RCTRequired - RCTTypeSafety - React @@ -731,9 +731,9 @@ SPEC CHECKSUMS: Airship: 02ad73780f9eed21870e36b0aaab327acda6a102 boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 - DoubleConversion: cf9b38bf0b2d048436d9a82ad2abe1404f11e7de + DoubleConversion: cde416483dac037923206447da6e1454df403714 FBLazyVector: 7b423f9e248eae65987838148c36eec1dbfe0b53 - FBReactNativeSpec: 1afb9713f8c77698352ab2effd491031b00c44f0 + FBReactNativeSpec: 884d4cc2b011759361797a4035c47e10099393b5 Firebase: c23a36d9e4cdf7877dfcba8dd0c58add66358999 FirebaseAnalytics: 3bb096873ee0d7fa4b6c70f5e9166b6da413cc7f FirebaseCore: d3a978a3cfa3240bf7e4ba7d137fdf5b22b628ec @@ -747,7 +747,7 @@ SPEC CHECKSUMS: Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 Flipper-RSocket: 127954abe8b162fcaf68d2134d34dc2bd7076154 FlipperKit: 8a20b5c5fcf9436cac58551dc049867247f64b00 - glog: 73c2498ac6884b13ede40eda8228cb1eee9d9d62 + glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3 GoogleAppMeasurement: a6a3a066369828db64eda428cb2856dc1cdc7c4e GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833 GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3 @@ -805,7 +805,7 @@ SPEC CHECKSUMS: RNFBCrashlytics: 4870c14cf8833053b6b5648911abefe1923854d2 RNGestureHandler: 9b7e605a741412e20e13c512738a31bd1611759b RNPermissions: eb94f9fdc0a8ecd02fcce0676d56ffb1395d41e1 - RNReanimated: 70f662b5232dd5d19ccff581e919a54ea73df51c + RNReanimated: b8c8004b43446e3c2709fe64b2b41072f87428ad RNScreens: e8e8dd0588b5da0ab57dcca76ab9b2d8987757e0 RNSVG: ce9d996113475209013317e48b05c21ee988d42e urbanairship-react-native: dfb6dc22b2f41ccaadd636b73d51b448cd1b2bbc diff --git a/package-lock.json b/package-lock.json index 0508be3f104b..4797885b1f1d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23142,9 +23142,9 @@ "dev": true }, "inline-style-prefixer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-5.1.2.tgz", - "integrity": "sha512-PYUF+94gDfhy+LsQxM0g3d6Hge4l1pAqOSOiZuHWzMvQEGsbRQ/ck2WioLqrY2ZkHyPgVUXxn+hrkF7D6QUGbA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-6.0.0.tgz", + "integrity": "sha512-XTHvRUS4ZJNzC1GixJRmOlWSS45fSt+DJoyQC9ytj0WxQfcgofQtDtyKKYxHUqEsWCs+LIWftPF1ie7+i012Fg==", "requires": { "css-in-js-utils": "^2.0.0" } @@ -32500,13 +32500,12 @@ } }, "react": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", - "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", + "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", "requires": { "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2" + "object-assign": "^4.1.1" } }, "react-colorful": { @@ -32889,20 +32888,19 @@ } }, "react-dom": { - "version": "16.14.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", - "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.19.1" + "scheduler": "^0.20.2" }, "dependencies": { "scheduler": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", - "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -33894,6 +33892,16 @@ } } }, + "react": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", + "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2" + } + }, "react-dom": { "version": "16.12.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.12.0.tgz", @@ -34181,19 +34189,43 @@ } }, "react-native-web": { - "version": "0.14.10", - "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.14.10.tgz", - "integrity": "sha512-YTvYnUUPnOjU50GiXk90cm6atk714vF8p7HhBlqHtLtftHk9xQRwgxXzoMHiKf0Bx20Dyo2SGvv4XrPxcmEheQ==", + "version": "0.15.7", + "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.15.7.tgz", + "integrity": "sha512-mrbQayl1luIO4Gfyw6KLdlWc30JcJOQgRn84iOj6dLJYVRwcE6W5U2Af68hQYFJsGgVb9sdlYC0ppfFM7ywqXQ==", "requires": { "array-find-index": "^1.0.2", - "create-react-class": "^15.6.2", + "create-react-class": "^15.7.0", "deep-assign": "^3.0.0", - "fbjs": "^1.0.0", - "hyphenate-style-name": "^1.0.3", - "inline-style-prefixer": "^5.1.0", + "fbjs": "^3.0.0", + "hyphenate-style-name": "^1.0.4", + "inline-style-prefixer": "^6.0.0", "normalize-css-color": "^1.0.2", "prop-types": "^15.6.0", "react-timer-mixin": "^0.13.4" + }, + "dependencies": { + "fbjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.0.tgz", + "integrity": "sha512-dJd4PiDOFuhe7vk4F80Mba83Vr2QuK86FoxtgPmzBqEJahncp+13YCmfoa53KHCo6OnlXLG7eeMWPfB5CrpVKg==", + "requires": { + "cross-fetch": "^3.0.4", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + } + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } + } } }, "react-pdf": { diff --git a/package.json b/package.json index 4f7b195e0101..d3cd90cc2676 100644 --- a/package.json +++ b/package.json @@ -32,8 +32,6 @@ "analyze-packages": "ANALYZE_BUNDLE=true webpack --config config/webpack/webpack.prod.js" }, "dependencies": { - "@babel/plugin-proposal-class-properties": "^7.12.1", - "@babel/preset-flow": "^7.12.13", "@formatjs/intl-getcanonicallocales": "^1.5.8", "@formatjs/intl-locale": "^2.4.21", "@formatjs/intl-numberformat": "^6.2.5", @@ -70,8 +68,8 @@ "onfido-sdk-ui": "^6.7.2", "prop-types": "^15.7.2", "pusher-js": "^7.0.0", - "react": "^16.13.1", - "react-dom": "^16.13.1", + "react": "^17.0.2", + "react-dom": "^17.0.2", "react-native": "0.64.1", "react-native-bootsplash": "^3.2.0", "react-native-config": "^1.4.0", @@ -92,7 +90,7 @@ "react-native-safe-area-context": "^3.1.4", "react-native-screens": "^3.0.0", "react-native-svg": "^12.1.0", - "react-native-web": "^0.14.1", + "react-native-web": "0.15.7", "react-pdf": "^5.2.0", "react-plaid-link": "^3.1.0", "react-web-config": "^1.0.0", @@ -105,6 +103,7 @@ "@actions/core": "^1.2.6", "@actions/github": "^4.0.0", "@babel/core": "^7.11.1", + "@babel/plugin-proposal-class-properties": "^7.12.1", "@babel/preset-env": "^7.11.0", "@babel/preset-flow": "^7.12.13", "@babel/preset-react": "^7.10.4", @@ -127,6 +126,7 @@ "babel-plugin-module-resolver": "^4.0.0", "babel-plugin-react-native-web": "^0.13.5", "babel-plugin-transform-class-properties": "^6.24.1", + "babel-plugin-transform-remove-console": "^6.9.4", "clean-webpack-plugin": "^3.0.0", "concurrently": "^5.3.0", "copy-webpack-plugin": "^6.0.3", diff --git a/src/components/InvertedFlatList/index.js b/src/components/InvertedFlatList/index.js index f56f74ce375c..a2dd20b2c999 100644 --- a/src/components/InvertedFlatList/index.js +++ b/src/components/InvertedFlatList/index.js @@ -1,7 +1,4 @@ import React, { - useEffect, - useRef, - useCallback, forwardRef, } from 'react'; import PropTypes from 'prop-types'; @@ -16,57 +13,58 @@ const propTypes = { }).isRequired, }; -// This is copied from https://codesandbox.io/s/react-native-dsyse +// This is adapted from https://codesandbox.io/s/react-native-dsyse // It's a HACK alert since FlatList has inverted scrolling on web -const InvertedFlatList = (props) => { - const ref = useRef(null); +class InvertedFlatList extends React.Component { + constructor(props) { + super(props); - const invertedWheelEvent = useCallback((e) => { - ref.current.getScrollableNode().scrollTop -= e.deltaY; - e.preventDefault(); - }, []); + this.invertedWheelEvent = this.invertedWheelEvent.bind(this); + this.list = undefined; + } - useEffect(() => { - if (!_.isFunction(props.innerRef)) { + componentDidMount() { + if (!_.isFunction(this.props.innerRef)) { // eslint-disable-next-line no-param-reassign - props.innerRef.current = ref.current; + this.props.innerRef.current = this.list; } else { - props.innerRef(ref.current); + this.props.innerRef(this.list); } - }, []); - useEffect(() => { - const currentRef = ref.current; - if (currentRef != null) { - currentRef + if (this.list) { + this.list .getScrollableNode() - .addEventListener('wheel', invertedWheelEvent); + .addEventListener('wheel', this.invertedWheelEvent); - currentRef.setNativeProps({ + this.list.setNativeProps({ style: { transform: 'translate3d(0,0,0) scaleY(-1)', }, }); } + } - return () => { - if (currentRef != null) { - currentRef - .getScrollableNode() - .removeEventListener('wheel', invertedWheelEvent); - } - }; - }, [ref, invertedWheelEvent]); + componentWillUnmount() { + this.list.getScrollableNode() + .removeEventListener('wheel', this.invertedWheelEvent); + } - return ( - - ); -}; + invertedWheelEvent(e) { + this.list.getScrollableNode().scrollTop -= e.deltaY; + e.preventDefault(); + } + + render() { + return ( + this.list = el} + shouldMeasureItems + /> + ); + } +} InvertedFlatList.propTypes = propTypes; diff --git a/src/components/TextLink.js b/src/components/TextLink.js index df271d88b4fa..2d35eb8f964d 100644 --- a/src/components/TextLink.js +++ b/src/components/TextLink.js @@ -1,8 +1,7 @@ import _ from 'underscore'; import React from 'react'; import PropTypes from 'prop-types'; -import {Text, Pressable} from 'react-native'; -import openURLInNewTab from '../libs/openURLInNewTab'; +import {Text, Pressable, Linking} from 'react-native'; import styles from '../styles/styles'; const propTypes = { @@ -26,7 +25,7 @@ const TextLink = (props) => { { e.preventDefault(); - openURLInNewTab(props.href); + Linking.openURL(props.href); }} accessibilityRole="link" href={props.href} diff --git a/src/components/Tooltip/index.js b/src/components/Tooltip/index.js index 694b899a9bfc..59ebaf0d41ff 100644 --- a/src/components/Tooltip/index.js +++ b/src/components/Tooltip/index.js @@ -135,6 +135,7 @@ class Tooltip extends PureComponent { toValue: 1, duration: 140, delay: 500, + useNativeDriver: false, }).start(); } }); @@ -149,6 +150,7 @@ class Tooltip extends PureComponent { Animated.timing(this.animation, { toValue: 0, duration: 140, + useNativeDriver: false, }).start(); } diff --git a/src/components/VideoChatButtonAndMenu.js b/src/components/VideoChatButtonAndMenu.js index cf9069483904..3c0de9a3dd6a 100755 --- a/src/components/VideoChatButtonAndMenu.js +++ b/src/components/VideoChatButtonAndMenu.js @@ -1,10 +1,11 @@ import React, {Component} from 'react'; -import {View, Pressable, Dimensions} from 'react-native'; +import { + View, Pressable, Dimensions, Linking, +} from 'react-native'; import Icon from './Icon'; import {Phone} from './Icon/Expensicons'; import Popover from './Popover'; import MenuItem from './MenuItem'; -import openURLInNewTab from '../libs/openURLInNewTab'; import ZoomIcon from '../../assets/images/zoom-icon.svg'; import GoogleMeetIcon from '../../assets/images/google-meet.svg'; import CONST from '../CONST'; @@ -30,12 +31,12 @@ class VideoChatButtonAndMenu extends Component { { icon: ZoomIcon, text: props.translate('videoChatButtonAndMenu.zoom'), - onPress: () => openURLInNewTab(CONST.NEW_ZOOM_MEETING_URL), + onPress: () => Linking.openURL(CONST.NEW_ZOOM_MEETING_URL), }, { icon: GoogleMeetIcon, text: props.translate('videoChatButtonAndMenu.googleMeet'), - onPress: () => openURLInNewTab(CONST.NEW_GOOGLE_MEET_MEETING_URL), + onPress: () => Linking.openURL(CONST.NEW_GOOGLE_MEET_MEETING_URL), }, ].map(item => ({ ...item, diff --git a/src/libs/Navigation/Navigation.js b/src/libs/Navigation/Navigation.js index 0ebab6f3ff67..7fe26fcf31d9 100644 --- a/src/libs/Navigation/Navigation.js +++ b/src/libs/Navigation/Navigation.js @@ -1,7 +1,6 @@ import _ from 'underscore'; import React from 'react'; import {StackActions, DrawerActions} from '@react-navigation/native'; -import {getIsDrawerOpenFromState} from '@react-navigation/drawer'; import Onyx from 'react-native-onyx'; import linkTo from './linkTo'; @@ -99,18 +98,8 @@ function dismissModal(shouldOpenDrawer = false) { openDrawer(); } -/** - * Determines whether the drawer is currently open. - * - * @returns {Boolean} - */ -function isDrawerOpen() { - return getIsDrawerOpenFromState(navigationRef.current.getRootState().routes[0].state); -} - export default { navigate, dismissModal, - isDrawerOpen, goBack, }; diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 06fc4acb4e4f..3e64047eedc8 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1,11 +1,11 @@ import Onyx from 'react-native-onyx'; +import {Linking} from 'react-native'; import _ from 'underscore'; import CONST from '../../CONST'; import ONYXKEYS from '../../ONYXKEYS'; import ROUTES from '../../ROUTES'; import * as API from '../API'; import {getSimplifiedIOUReport, fetchChatReportsByIDs, fetchIOUReportByIDAndUpdateChatReport} from './Report'; -import openURLInNewTab from '../openURLInNewTab'; import Navigation from '../Navigation/Navigation'; /** @@ -216,9 +216,9 @@ function payIOUReport({ // Once we have successfully paid the IOU we will transfer the user to their platform of choice if they have // selected something other than a manual settlement or Expensify Wallet e.g. Venmo or PayPal.me if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.PAYPAL_ME) { - openURLInNewTab(buildPayPalPaymentUrl(amount, submitterPayPalMeAddress, currency)); + Linking.openURL(buildPayPalPaymentUrl(amount, submitterPayPalMeAddress, currency)); } else if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.VENMO) { - openURLInNewTab(buildVenmoPaymentURL(amount, submitterPhoneNumber)); + Linking.openURL(buildVenmoPaymentURL(amount, submitterPhoneNumber)); } }) .catch((error) => { diff --git a/src/libs/fileDownload/index.js b/src/libs/fileDownload/index.js index 20d6e0a948de..5d01e703f3a7 100644 --- a/src/libs/fileDownload/index.js +++ b/src/libs/fileDownload/index.js @@ -1,4 +1,4 @@ -import openURLInNewTab from '../openURLInNewTab'; +import {Linking} from 'react-native'; import getAttachmentName from './getAttachmentName'; /** @@ -36,6 +36,6 @@ export default function fileDownload(url) { link.parentNode.removeChild(link); }).catch(() => { // file could not be downloaded, open sourceURL in new tab - openURLInNewTab(url); + Linking.openURL(url); }); } diff --git a/src/libs/openURLInNewTab/index.js b/src/libs/openURLInNewTab/index.js deleted file mode 100644 index f0d529c1894b..000000000000 --- a/src/libs/openURLInNewTab/index.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * On web, the Linking.openURL implementation does not open a URL in a new tab by default. This lib allows for that - * functionality. - */ - -/** - * @param {String} href - */ -const openURLInNewTab = (href) => { - window.open(href, '_blank'); -}; - -export default openURLInNewTab; diff --git a/src/libs/openURLInNewTab/index.native.js b/src/libs/openURLInNewTab/index.native.js deleted file mode 100644 index e11f276df421..000000000000 --- a/src/libs/openURLInNewTab/index.native.js +++ /dev/null @@ -1,12 +0,0 @@ -// Mobile implementation to match the web lib, this will open the URL in the browser - -import {Linking} from 'react-native'; - -/** - * @param {String} href - */ -const openURLInNewTab = (href) => { - Linking.openURL(href); -}; - -export default openURLInNewTab; diff --git a/src/pages/home/report/ReportActionContextMenuItem.js b/src/pages/home/report/ReportActionContextMenuItem.js index 64d8637a5aec..ae2905d7b274 100644 --- a/src/pages/home/report/ReportActionContextMenuItem.js +++ b/src/pages/home/report/ReportActionContextMenuItem.js @@ -68,7 +68,7 @@ class ReportActionContextMenuItem extends Component { ? ( { icon: Eye, iconRight: NewWindow, action: () => { - openURLInNewTab(CONST.GITHUB_URL); + Linking.openURL(CONST.GITHUB_URL); }, }, { @@ -59,7 +58,7 @@ const AboutPage = ({translate, session}) => { icon: MoneyBag, iconRight: NewWindow, action: () => { - openURLInNewTab(CONST.UPWORK_URL); + Linking.openURL(CONST.UPWORK_URL); }, }, { @@ -129,7 +128,7 @@ const AboutPage = ({translate, session}) => { {' '} openURLInNewTab(CONST.TERMS_URL)} + onPress={() => Linking.openURL(CONST.TERMS_URL)} > {translate( 'initialSettingsPage.readTheTermsAndPrivacyPolicy.phrase2', @@ -142,7 +141,7 @@ const AboutPage = ({translate, session}) => { {' '} openURLInNewTab(CONST.PRIVACY_URL)} + onPress={() => Linking.openURL(CONST.PRIVACY_URL)} > {translate( 'initialSettingsPage.readTheTermsAndPrivacyPolicy.phrase4', diff --git a/src/pages/settings/AppDownloadLinks.js b/src/pages/settings/AppDownloadLinks.js index 7ba68b3b07e1..4d0543b2718b 100644 --- a/src/pages/settings/AppDownloadLinks.js +++ b/src/pages/settings/AppDownloadLinks.js @@ -1,5 +1,5 @@ import React from 'react'; -import {ScrollView} from 'react-native'; +import {ScrollView, Linking} from 'react-native'; import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; import Navigation from '../../libs/Navigation/Navigation'; import CONST from '../../CONST'; @@ -10,7 +10,6 @@ import ScreenWrapper from '../../components/ScreenWrapper'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; import compose from '../../libs/compose'; import MenuItem from '../../components/MenuItem'; -import openURLInNewTab from '../../libs/openURLInNewTab'; import styles from '../../styles/styles'; const propTypes = { @@ -23,19 +22,19 @@ const AppDownloadLinksPage = ({translate}) => { translationKey: 'initialSettingsPage.appDownloadLinks.android.label', icon: Android, iconRight: NewWindow, - action: () => { openURLInNewTab(CONST.APP_DOWNLOAD_LINKS.ANDROID); }, + action: () => { Linking.openURL(CONST.APP_DOWNLOAD_LINKS.ANDROID); }, }, { translationKey: 'initialSettingsPage.appDownloadLinks.ios.label', icon: Apple, iconRight: NewWindow, - action: () => { openURLInNewTab(CONST.APP_DOWNLOAD_LINKS.IOS); }, + action: () => { Linking.openURL(CONST.APP_DOWNLOAD_LINKS.IOS); }, }, { translationKey: 'initialSettingsPage.appDownloadLinks.desktop.label', icon: Monitor, iconRight: NewWindow, - action: () => { openURLInNewTab(CONST.APP_DOWNLOAD_LINKS.DESKTOP); }, + action: () => { Linking.openURL(CONST.APP_DOWNLOAD_LINKS.DESKTOP); }, }, ];