diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index 755ab6dbaa60..6ded44d7059f 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -354,6 +354,6 @@ jobs: IOS: ${{ needs.iOS.result }} WEB: ${{ needs.web.result }} ANDROID_LINK: ${{steps.get_android_path.outputs.android_path}} - DESKTOP_LINK: https://ad-hoc-expensify-cash.s3.amazonaws.com/desktop/${{ env.PULL_REQUEST_NUMBER }}/NewExpensifyAdHoc.dmg + DESKTOP_LINK: https://ad-hoc-expensify-cash.s3.amazonaws.com/desktop/${{ env.PULL_REQUEST_NUMBER }}/NewExpensify.dmg IOS_LINK: ${{steps.get_ios_path.outputs.ios_path}} WEB_LINK: https://${{ env.PULL_REQUEST_NUMBER }}.pr-testing.expensify.com diff --git a/.storybook/theme.js b/.storybook/theme.js index 0867f6a830b5..96631764726f 100644 --- a/.storybook/theme.js +++ b/.storybook/theme.js @@ -7,17 +7,17 @@ export default create({ fontBase: 'ExpensifyNeue-Regular', fontCode: 'monospace', base: 'dark', - appBg: colors.greenHighlightBackground, - colorPrimary: colors.greenDefaultButton, + appBg: colors.darkHighlightBackground, + colorPrimary: colors.darkDefaultButton, colorSecondary: colors.green, - appContentBg: colors.greenAppBackground, - textColor: colors.white, - barTextColor: colors.white, + appContentBg: colors.darkAppBackground, + textColor: colors.darkPrimaryText, + barTextColor: colors.darkPrimaryText, barSelectedColor: colors.green, - barBg: colors.greenAppBackground, - appBorderColor: colors.greenBorders, - inputBg: colors.greenHighlightBackground, - inputBorder: colors.greenBorders, + barBg: colors.darkAppBackground, + appBorderColor: colors.darkBorders, + inputBg: colors.darkHighlightBackground, + inputBorder: colors.darkBorders, appBorderRadius: 8, inputBorderRadius: 8, }); diff --git a/android/app/build.gradle b/android/app/build.gradle index 1867a8cf85d2..d9eb60471773 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -90,8 +90,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001037002 - versionName "1.3.70-2" + versionCode 1001037005 + versionName "1.3.70-5" } flavorDimensions "default" diff --git a/config/electronBuilder.config.js b/config/electronBuilder.config.js index a5478dbd8f78..da87c93ee367 100644 --- a/config/electronBuilder.config.js +++ b/config/electronBuilder.config.js @@ -21,24 +21,6 @@ const macIcon = { adhoc: './desktop/icon-adhoc.png', }; -const appIds = { - production: 'com.expensifyreactnative.chat', - staging: 'com.expensifyreactnative.dev.chat', - adhoc: 'com.expensifyreactnative.adhoc.chat', -}; - -const productNames = { - production: 'New Expensify', - staging: 'New Expensify Dev', - adhoc: 'New Expensify AdHoc', -}; - -const artifactNames = { - production: 'NewExpensify.dmg', - staging: 'NewExpensifyDev.dmg', - adhoc: 'NewExpensifyAdHoc.dmg', -}; - const isCorrectElectronEnv = ['production', 'staging', 'adhoc'].includes(process.env.ELECTRON_ENV); if (!isCorrectElectronEnv) { @@ -50,8 +32,8 @@ if (!isCorrectElectronEnv) { * It can be used to create local builds of the same, by omitting the `--publish` flag */ module.exports = { - appId: appIds[process.env.ELECTRON_ENV], - productName: productNames[process.env.ELECTRON_ENV], + appId: 'com.expensifyreactnative.chat', + productName: 'New Expensify', extraMetadata: { version, }, @@ -64,8 +46,8 @@ module.exports = { type: 'distribution', }, dmg: { - title: productNames[process.env.ELECTRON_ENV], - artifactName: artifactNames[process.env.ELECTRON_ENV], + title: 'New Expensify', + artifactName: 'NewExpensify.dmg', internetEnabled: true, }, publish: [ @@ -83,7 +65,7 @@ module.exports = { output: 'desktop-build', }, protocols: { - name: productNames[process.env.ELECTRON_ENV], + name: 'New Expensify', schemes: ['new-expensify'], }, }; diff --git a/docs/assets/js/main.js b/docs/assets/js/main.js index 01ebb00b288c..f0f335536c20 100644 --- a/docs/assets/js/main.js +++ b/docs/assets/js/main.js @@ -206,13 +206,6 @@ window.addEventListener('DOMContentLoaded', () => { // If there is a fixed article scroll container, set to calculate titles' offset scrollContainer: 'content-area', - - // onclick function to apply to all links in toc. will be called with - // the event as the first parameter, and this can be used to stop, - // propagation, prevent default or perform action - onClick() { - toggleHeaderMenu(); - }, }); } @@ -226,6 +219,18 @@ window.addEventListener('DOMContentLoaded', () => { const articleContent = document.getElementById('article-content'); const lhnContent = document.getElementById('lhn-content'); + + // This event listener checks if a link clicked in the LHN points to some section of the same page and toggles + // the LHN menu in responsive view. + lhnContent.addEventListener('click', (event) => { + const clickedLink = event.target; + if (clickedLink) { + const href = clickedLink.getAttribute('href'); + if (href && href.startsWith('#') && !!document.getElementById(href.slice(1))) { + toggleHeaderMenu(); + } + } + }); lhnContent.addEventListener('wheel', (e) => { const scrollTop = lhnContent.scrollTop; const isScrollingPastLHNTop = e.deltaY < 0 && scrollTop === 0; diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 9e4501eddea5..440e48e0c83d 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.3.70.2 + 1.3.70.5 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index fd93684a1da3..9d7fc804acd9 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.3.70.2 + 1.3.70.5 diff --git a/package-lock.json b/package-lock.json index f36d0e88f52b..3e08356a76ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.3.70-2", + "version": "1.3.70-5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.3.70-2", + "version": "1.3.70-5", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -65,7 +65,7 @@ "patch-package": "^8.0.0", "process": "^0.11.10", "prop-types": "^15.7.2", - "pusher-js": "7.4.0", + "pusher-js": "8.3.0", "react": "18.2.0", "react-collapse": "^5.1.0", "react-content-loader": "^6.1.0", @@ -39745,10 +39745,10 @@ } }, "node_modules/pusher-js": { - "version": "7.4.0", - "license": "MIT", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-8.3.0.tgz", + "integrity": "sha512-6GohP06WlVeomAQQe9qWh1IDzd3+InluWt+ZUOcecVK1SEQkg6a8uYVsvxSJm7cbccfmHhE0jDkmhKIhue8vmA==", "dependencies": { - "@types/node": "^14.14.31", "tweetnacl": "^1.0.3" } }, @@ -39760,11 +39760,6 @@ "node": ">=4.2.4" } }, - "node_modules/pusher-js/node_modules/@types/node": { - "version": "14.18.56", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.56.tgz", - "integrity": "sha512-+k+57NVS9opgrEn5l9c0gvD1r6C+PtyhVE4BTnMMRwiEA8ZO8uFcs6Yy2sXIy0eC95ZurBtRSvhZiHXBysbl6w==" - }, "node_modules/qrcode": { "version": "1.5.3", "license": "MIT", @@ -75499,17 +75494,11 @@ "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" }, "pusher-js": { - "version": "7.4.0", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-8.3.0.tgz", + "integrity": "sha512-6GohP06WlVeomAQQe9qWh1IDzd3+InluWt+ZUOcecVK1SEQkg6a8uYVsvxSJm7cbccfmHhE0jDkmhKIhue8vmA==", "requires": { - "@types/node": "^14.14.31", "tweetnacl": "^1.0.3" - }, - "dependencies": { - "@types/node": { - "version": "14.18.56", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.56.tgz", - "integrity": "sha512-+k+57NVS9opgrEn5l9c0gvD1r6C+PtyhVE4BTnMMRwiEA8ZO8uFcs6Yy2sXIy0eC95ZurBtRSvhZiHXBysbl6w==" - } } }, "pusher-js-mock": { diff --git a/package.json b/package.json index 315d01ea5dc3..221c3fa7cbf2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.3.70-2", + "version": "1.3.70-5", "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.", @@ -107,7 +107,7 @@ "patch-package": "^8.0.0", "process": "^0.11.10", "prop-types": "^15.7.2", - "pusher-js": "7.4.0", + "pusher-js": "8.3.0", "react": "18.2.0", "react-collapse": "^5.1.0", "react-content-loader": "^6.1.0", diff --git a/src/CONST.ts b/src/CONST.ts index 1ef2f3e83246..93576e0ccf9d 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -293,8 +293,8 @@ const CONST = { }, type: KEYBOARD_SHORTCUT_NAVIGATION_TYPE, }, - NEW_GROUP: { - descriptionKey: 'newGroup', + NEW_CHAT: { + descriptionKey: 'newChat', shortcutKey: 'K', modifiers: ['CTRL', 'SHIFT'], trigger: { @@ -1342,6 +1342,7 @@ const CONST = { SETTINGS: 'settings', LEAVE_ROOM: 'leaveRoom', WELCOME_MESSAGE: 'welcomeMessage', + PRIVATE_NOTES: 'privateNotes', }, EDIT_REQUEST_FIELD: { AMOUNT: 'amount', @@ -2624,6 +2625,9 @@ const CONST = { DISABLED: 'DISABLED', }, TAB: { + NEW_CHAT_TAB_ID: 'NewChatTab', + NEW_CHAT: 'chat', + NEW_ROOM: 'room', RECEIPT_TAB_ID: 'ReceiptTab', MANUAL: 'manual', SCAN: 'scan', diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 2e0b75910bae..80afc4d5ffee 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -290,6 +290,7 @@ const ONYXKEYS = { SETTINGS_STATUS_SET_FORM: 'settingsStatusSetForm', SETTINGS_STATUS_CLEAR_AFTER_FORM: 'settingsStatusClearAfterForm', SETTINGS_STATUS_SET_CLEAR_AFTER_FORM: 'settingsStatusSetClearAfterForm', + PRIVATE_NOTES_FORM: 'privateNotesForm', I_KNOW_A_TEACHER_FORM: 'iKnowTeacherForm', INTRO_SCHOOL_PRINCIPAL_FORM: 'introSchoolPrincipalForm', }, diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 3bbdf4709cfc..9459708c893b 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -13,7 +13,6 @@ type ParseReportRouteParams = { const REPORT = 'r'; const IOU_REQUEST = 'request/new'; -const IOU_BILL = 'split/new'; const IOU_SEND = 'send/new'; const NEW_TASK = 'new/task'; const SETTINGS_PERSONAL_DETAILS = 'settings/profile/personal-details'; @@ -67,11 +66,12 @@ export default { SETTINGS_2FA: 'settings/security/two-factor-auth', SETTINGS_STATUS, SETTINGS_STATUS_SET, - NEW_GROUP: 'new/group', + NEW: 'new', NEW_CHAT: 'new/chat', + NEW_ROOM: 'new/room', NEW_TASK, REPORT, - REPORT_WITH_ID: 'r/:reportID/:reportActionID?', + REPORT_WITH_ID: 'r/:reportID?/:reportActionID?', EDIT_REQUEST: 'r/:threadReportID/edit/:field', getEditRequestRoute: (threadReportID: string, field: ValueOf) => `r/${threadReportID}/edit/${field}`, EDIT_CURRENCY_REQUEST: 'r/:threadReportID/edit/currency', @@ -86,7 +86,6 @@ export default { CONCIERGE: 'concierge', IOU_REQUEST, - IOU_BILL, IOU_SEND, // To see the available iouType, please refer to CONST.IOU.MONEY_REQUEST_TYPE @@ -104,6 +103,7 @@ export default { MONEY_REQUEST_SCAN_TAB: ':iouType/new/:reportID?/scan', MONEY_REQUEST_DISTANCE_TAB: ':iouType/new/:reportID?/distance', MONEY_REQUEST_WAYPOINT: ':iouType/new/waypoint/:waypointIndex', + MONEY_REQUEST_ADDRESS: ':iouType/new/address/:reportID?', IOU_SEND_ADD_BANK_ACCOUNT: `${IOU_SEND}/add-bank-account`, IOU_SEND_ADD_DEBIT_CARD: `${IOU_SEND}/add-debit-card`, IOU_SEND_ENABLE_PAYMENTS: `${IOU_SEND}/enable-payments`, @@ -118,6 +118,7 @@ export default { getMoneyRequestMerchantRoute: (iouType: string, reportID = '') => `${iouType}/new/merchant/${reportID}`, getMoneyRequestDistanceTabRoute: (iouType: string, reportID = '') => `${iouType}/new/${reportID}/distance`, getMoneyRequestWaypointRoute: (iouType: string, waypointIndex: number) => `${iouType}/new/waypoint/${waypointIndex}`, + getMoneyRequestAddressRoute: (iouType: string, reportID = '') => `${iouType}/new/address/${reportID}`, getMoneyRequestTagRoute: (iouType: string, reportID = '') => `${iouType}/new/tag/${reportID}`, SPLIT_BILL_DETAILS: `r/:reportID/split/:reportActionID`, getSplitBillDetailsRoute: (reportID: string, reportActionID: string) => `r/${reportID}/split/${reportActionID}`, @@ -172,6 +173,14 @@ export default { GOOGLE_SIGN_IN: 'sign-in-with-google', DESKTOP_SIGN_IN_REDIRECT: 'desktop-signin-redirect', + // Routes related to private notes added to the report + PRIVATE_NOTES_VIEW: 'r/:reportID/notes/:accountID', + getPrivateNotesViewRoute: (reportID: string, accountID: string | number) => `r/${reportID}/notes/${accountID}`, + PRIVATE_NOTES_LIST: 'r/:reportID/notes', + getPrivateNotesListRoute: (reportID: string) => `r/${reportID}/notes`, + PRIVATE_NOTES_EDIT: 'r/:reportID/notes/:accountID/edit', + getPrivateNotesEditRoute: (reportID: string, accountID: string | number) => `r/${reportID}/notes/${accountID}/edit`, + // This is a special validation URL that will take the user to /workspace/new after validation. This is used // when linking users from e.com in order to share a session in this app. ENABLE_PAYMENTS: 'enable-payments', diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js index dbe7e46ff6aa..e2843ba7fae8 100644 --- a/src/components/AddPlaidBankAccount.js +++ b/src/components/AddPlaidBankAccount.js @@ -1,6 +1,7 @@ import _ from 'underscore'; -import React, {useEffect, useRef, useCallback} from 'react'; +import React, {useEffect, useRef, useCallback, useMemo} from 'react'; import {ActivityIndicator, View} from 'react-native'; +import {useIsFocused} from '@react-navigation/native'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; import lodashGet from 'lodash/get'; @@ -38,6 +39,9 @@ const propTypes = { /** Fired when the user exits the Plaid flow */ onExitPlaid: PropTypes.func, + /** Fired when the screen is blurred */ + onBlurPlaid: PropTypes.func, + /** Fired when the user selects an account */ onSelect: PropTypes.func, @@ -61,6 +65,7 @@ const defaultProps = { selectedPlaidAccountID: '', plaidLinkToken: '', onExitPlaid: () => {}, + onBlurPlaid: () => {}, onSelect: () => {}, text: '', receivedRedirectURI: null, @@ -75,6 +80,7 @@ function AddPlaidBankAccount({ selectedPlaidAccountID, plaidLinkToken, onExitPlaid, + onBlurPlaid, onSelect, text, receivedRedirectURI, @@ -88,6 +94,7 @@ function AddPlaidBankAccount({ const {translate} = useLocalize(); const {isOffline} = useNetwork(); + const isFocused = useIsFocused(); /** * @returns {String} @@ -102,6 +109,11 @@ function AddPlaidBankAccount({ } }; + /** + * @returns {Array} + */ + const plaidBankAccounts = useMemo(() => lodashGet(plaidData, 'bankAccounts') || [], [plaidData]); + /** * @returns {Boolean} * I'm using useCallback so the useEffect which uses this function doesn't run on every render. @@ -151,6 +163,13 @@ function AddPlaidBankAccount({ // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + useEffect(() => { + if (isFocused || plaidBankAccounts.length) { + return; + } + onBlurPlaid(); + }, [isFocused, onBlurPlaid, plaidBankAccounts.length]); + useEffect(() => { // If we are coming back from offline and we haven't authenticated with Plaid yet, we need to re-run our call to kick off Plaid // previousNetworkState.current also makes sure that this doesn't run on the first render. @@ -160,7 +179,6 @@ function AddPlaidBankAccount({ previousNetworkState.current = isOffline; }, [allowDebit, bankAccountID, isAuthenticatedWithPlaid, isOffline]); - const plaidBankAccounts = lodashGet(plaidData, 'bankAccounts') || []; const token = getPlaidLinkToken(); const options = _.map(plaidBankAccounts, (account) => ({ value: account.plaidAccountID, diff --git a/src/components/AnimatedStep/index.js b/src/components/AnimatedStep/index.js index a8b9b80fcc0e..5b0dc8bc78fa 100644 --- a/src/components/AnimatedStep/index.js +++ b/src/components/AnimatedStep/index.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import * as Animatable from 'react-native-animatable'; import CONST from '../../CONST'; import styles from '../../styles/styles'; +import useNativeDriver from '../../libs/useNativeDriver'; const propTypes = { /** Children to wrap in AnimatedStep. */ @@ -47,7 +48,7 @@ function AnimatedStep(props) { }} duration={CONST.ANIMATED_TRANSITION} animation={getAnimationStyle(props.direction)} - useNativeDriver + useNativeDriver={useNativeDriver} style={props.style} > {props.children} diff --git a/src/components/AttachmentModal.js b/src/components/AttachmentModal.js index d39906faf3a3..bbb0662132d2 100755 --- a/src/components/AttachmentModal.js +++ b/src/components/AttachmentModal.js @@ -25,6 +25,7 @@ import HeaderGap from './HeaderGap'; import SafeAreaConsumer from './SafeAreaConsumer'; import addEncryptedAuthTokenToURL from '../libs/addEncryptedAuthTokenToURL'; import reportPropTypes from '../pages/reportPropTypes'; +import useNativeDriver from '../libs/useNativeDriver'; /** * Modal render prop component that exposes modal launching triggers that can be used @@ -294,7 +295,7 @@ function AttachmentModal(props) { Animated.timing(confirmButtonFadeAnimation, { toValue, duration: 100, - useNativeDriver: true, + useNativeDriver, }).start(); }, [confirmButtonFadeAnimation], diff --git a/src/components/ConfirmedRoute.js b/src/components/ConfirmedRoute.js index 6790e8ae4d65..4bcdc4738a3c 100644 --- a/src/components/ConfirmedRoute.js +++ b/src/components/ConfirmedRoute.js @@ -16,7 +16,7 @@ import transactionPropTypes from './transactionPropTypes'; import BlockingView from './BlockingViews/BlockingView'; import useNetwork from '../hooks/useNetwork'; import useLocalize from '../hooks/useLocalize'; -import MapView from './MapView'; +import DistanceMapView from './DistanceMapView'; const propTypes = { /** Transaction that stores the distance request data */ @@ -90,7 +90,7 @@ function ConfirmedRoute({mapboxAccessToken, transaction}) { return ( <> {!isOffline && Boolean(mapboxAccessToken.token) ? ( - diff --git a/src/components/DistanceMapView/distanceMapViewPropTypes.js b/src/components/DistanceMapView/distanceMapViewPropTypes.js new file mode 100644 index 000000000000..05068cbc9b34 --- /dev/null +++ b/src/components/DistanceMapView/distanceMapViewPropTypes.js @@ -0,0 +1,55 @@ +import PropTypes from 'prop-types'; + +const propTypes = { + // Public access token to be used to fetch map data from Mapbox. + accessToken: PropTypes.string.isRequired, + + // Style applied to MapView component. Note some of the View Style props are not available on ViewMap + style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]), + + // Link to the style JSON document. + styleURL: PropTypes.string, + + // Whether map can tilt in the vertical direction. + pitchEnabled: PropTypes.bool, + + // Padding to apply when the map is adjusted to fit waypoints and directions + mapPadding: PropTypes.number, + + // Initial coordinate and zoom level + initialState: PropTypes.shape({ + location: PropTypes.arrayOf(PropTypes.number).isRequired, + zoom: PropTypes.number.isRequired, + }), + + // Locations on which to put markers + waypoints: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string, + coordinate: PropTypes.arrayOf(PropTypes.number), + markerComponent: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), + }), + ), + + // List of coordinates which together forms a direction. + directionCoordinates: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number)), + + // Callback to call when the map is idle / ready + onMapReady: PropTypes.func, + + // Optional additional styles to be applied to the overlay + overlayStyle: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]), +}; + +const defaultProps = { + styleURL: undefined, + pitchEnabled: false, + mapPadding: 0, + initialState: undefined, + waypoints: undefined, + directionCoordinates: undefined, + onMapReady: () => {}, + overlayStyle: undefined, +}; + +export {propTypes, defaultProps}; diff --git a/src/components/DistanceMapView/index.android.js b/src/components/DistanceMapView/index.android.js new file mode 100644 index 000000000000..ea72fb4de299 --- /dev/null +++ b/src/components/DistanceMapView/index.android.js @@ -0,0 +1,48 @@ +import React, {useState} from 'react'; +import {View} from 'react-native'; +import _ from 'underscore'; +import BlockingView from '../BlockingViews/BlockingView'; +import MapView from '../MapView'; +import styles from '../../styles/styles'; +import useNetwork from '../../hooks/useNetwork'; +import useLocalize from '../../hooks/useLocalize'; +import * as Expensicons from '../Icon/Expensicons'; +import * as StyleUtils from '../../styles/StyleUtils'; +import * as distanceMapViewPropTypes from './distanceMapViewPropTypes'; + +function DistanceMapView(props) { + const [isMapReady, setIsMapReady] = useState(false); + const {isOffline} = useNetwork(); + const {translate} = useLocalize(); + + return ( + <> + { + if (isMapReady) { + return; + } + setIsMapReady(true); + }} + /> + {!isMapReady && ( + + + + )} + + ); +} + +DistanceMapView.propTypes = distanceMapViewPropTypes.propTypes; +DistanceMapView.defaultProps = distanceMapViewPropTypes.defaultProps; +DistanceMapView.displayName = 'DistanceMapView'; + +export default DistanceMapView; diff --git a/src/components/DistanceMapView/index.js b/src/components/DistanceMapView/index.js new file mode 100644 index 000000000000..24bdf99382d1 --- /dev/null +++ b/src/components/DistanceMapView/index.js @@ -0,0 +1,15 @@ +import React from 'react'; +import _ from 'underscore'; +import MapView from '../MapView'; +import * as distanceMapViewPropTypes from './distanceMapViewPropTypes'; + +function DistanceMapView(props) { + // eslint-disable-next-line react/jsx-props-no-spreading + return ; +} + +DistanceMapView.propTypes = distanceMapViewPropTypes.propTypes; +DistanceMapView.defaultProps = distanceMapViewPropTypes.defaultProps; +DistanceMapView.displayName = 'DistanceMapView'; + +export default DistanceMapView; diff --git a/src/components/DistanceRequest.js b/src/components/DistanceRequest.js index 9de98f365475..bf5a4cb9548b 100644 --- a/src/components/DistanceRequest.js +++ b/src/components/DistanceRequest.js @@ -26,9 +26,10 @@ import Navigation from '../libs/Navigation/Navigation'; import * as MapboxToken from '../libs/actions/MapboxToken'; import * as Transaction from '../libs/actions/Transaction'; import * as TransactionUtils from '../libs/TransactionUtils'; +import * as IOUUtils from '../libs/IOUUtils'; import Button from './Button'; -import MapView from './MapView'; +import DistanceMapView from './DistanceMapView'; import LinearGradient from './LinearGradient'; import * as Expensicons from './Icon/Expensicons'; import BlockingView from './BlockingViews/BlockingView'; @@ -38,6 +39,9 @@ import {iouPropTypes} from '../pages/iou/propTypes'; import reportPropTypes from '../pages/reportPropTypes'; import * as IOU from '../libs/actions/IOU'; import * as StyleUtils from '../styles/StyleUtils'; +import ScreenWrapper from './ScreenWrapper'; +import FullPageNotFoundView from './BlockingViews/FullPageNotFoundView'; +import HeaderWithBackButton from './HeaderWithBackButton'; const MAX_WAYPOINTS = 25; const MAX_WAYPOINTS_TO_DISPLAY = 4; @@ -63,6 +67,18 @@ const propTypes = { /** Time when the token will expire in ISO 8601 */ expiration: PropTypes.string, }), + + /** React Navigation route */ + route: PropTypes.shape({ + /** Params from the route */ + params: PropTypes.shape({ + /** The type of IOU report, i.e. bill, request, send */ + iouType: PropTypes.string, + + /** The report ID of the IOU */ + reportID: PropTypes.string, + }), + }).isRequired, }; const defaultProps = { @@ -75,13 +91,14 @@ const defaultProps = { }, }; -function DistanceRequest({iou, iouType, report, transaction, mapboxAccessToken}) { +function DistanceRequest({iou, iouType, report, transaction, mapboxAccessToken, route}) { const [shouldShowGradient, setShouldShowGradient] = useState(false); const [scrollContainerHeight, setScrollContainerHeight] = useState(0); const [scrollContentHeight, setScrollContentHeight] = useState(0); const {isOffline} = useNetwork(); const {translate} = useLocalize(); + const isEditing = lodashGet(route, 'path', '').includes('address'); const reportID = lodashGet(report, 'reportID', ''); const waypoints = useMemo(() => lodashGet(transaction, 'comment.waypoints', {}), [transaction]); const previousWaypoints = usePrevious(waypoints); @@ -170,7 +187,20 @@ function DistanceRequest({iou, iouType, report, transaction, mapboxAccessToken}) useEffect(updateGradientVisibility, [scrollContainerHeight, scrollContentHeight]); - return ( + const navigateBack = () => { + Navigation.goBack(isEditing ? ROUTES.getMoneyRequestConfirmationRoute(iouType, reportID) : null); + }; + + const navigateToNextPage = () => { + if (isEditing) { + Navigation.goBack(ROUTES.getMoneyRequestConfirmationRoute(iouType, reportID)); + return; + } + + IOU.navigateToNextPage(iou, iouType, reportID, report); + }; + + const content = ( {!isOffline && Boolean(mapboxAccessToken.token) ? ( - ) : ( @@ -265,12 +296,35 @@ function DistanceRequest({iou, iouType, report, transaction, mapboxAccessToken})