Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added option to get user's current location #26546

Merged
merged 59 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
cd8cb9b
Added getCurrentPosition util
huzaifa-99 Sep 1, 2023
27f52d2
Added option to use current location in waypoint select
huzaifa-99 Sep 1, 2023
6d55057
Keep suggestion open on empty text with predefined suggestions
huzaifa-99 Sep 1, 2023
4f3c0ff
Disable current location button when offline
huzaifa-99 Sep 1, 2023
8203e03
Updated translation keys for address search hint
huzaifa-99 Sep 1, 2023
a55358c
Updated config for getting current location
huzaifa-99 Sep 1, 2023
f718ed6
Disable text select on current location button when offline
huzaifa-99 Sep 2, 2023
98f7570
Added missing comma in spanish translation
huzaifa-99 Sep 2, 2023
c2d67b8
Updated current location timeout to 5 seconds
huzaifa-99 Sep 2, 2023
1221d12
Updated function name
huzaifa-99 Sep 2, 2023
1be54a1
Use sentense case for comments
huzaifa-99 Sep 2, 2023
c097915
Move success/error callbacks inline
huzaifa-99 Sep 2, 2023
fa5aaef
Used index.platform file format for getCurrentPosition lib
huzaifa-99 Sep 2, 2023
befbb1f
Updated locationErrorCode prop type
huzaifa-99 Sep 2, 2023
fab2259
Moved navigator callback outside component body
huzaifa-99 Sep 2, 2023
19d0742
Updated desktop geolocation implementation
huzaifa-99 Sep 2, 2023
f7654d6
Prevent saving current location waypoint as recent wauypoint
huzaifa-99 Sep 2, 2023
cc97747
Updated location error text style
huzaifa-99 Sep 3, 2023
67c7c8a
Added location permission in android manifest
huzaifa-99 Sep 3, 2023
45947ce
Show system location enable prompt for geolocation on android
huzaifa-99 Sep 3, 2023
a7f6e18
Fix action argument type doc
huzaifa-99 Sep 3, 2023
7656511
Fix lint
huzaifa-99 Sep 4, 2023
f4ee7d7
Added loader when fetching location
huzaifa-99 Sep 4, 2023
fb37344
Prevent modal close on location fetch
huzaifa-99 Sep 4, 2023
40792cc
Moved location callback branch case to UserCurrentLocationButton
huzaifa-99 Sep 4, 2023
e0be146
Merge branch 'main' into 25855-get-user-location
huzaifa-99 Sep 6, 2023
79c187d
Hide keyboard immediately after clicking 'current location' btn
huzaifa-99 Sep 6, 2023
cb65a73
Merge branch 'main' into 25855-get-user-location
huzaifa-99 Sep 15, 2023
49c619b
Added null as default for locationErrorCode prop
huzaifa-99 Sep 18, 2023
08debbc
Inlined User.clearLocationError function call
huzaifa-99 Sep 18, 2023
809a449
Added comment for onyx props
huzaifa-99 Sep 18, 2023
1d31921
Updated location not found translation
huzaifa-99 Sep 18, 2023
1122848
Updated JSDoc for function definition
huzaifa-99 Sep 18, 2023
7d7f05f
Remove react-native-geolocation lib
huzaifa-99 Sep 18, 2023
07d3da3
Updated locationErrorCode proptype
huzaifa-99 Sep 18, 2023
393d582
Updated location error link style
huzaifa-99 Sep 18, 2023
b1a7da2
Filter 'Your Location' from recent waypoints without flag param
huzaifa-99 Sep 20, 2023
774fcd1
Updated navigator branch condition
huzaifa-99 Sep 20, 2023
50680b4
Merge branch 'main' into 25855-get-user-location
huzaifa-99 Sep 20, 2023
caa536d
Merge branch 'main' into 25855-get-user-location
huzaifa-99 Sep 21, 2023
7f309ad
Reverted undefined check
huzaifa-99 Sep 21, 2023
63b4379
Fix lint
huzaifa-99 Sep 21, 2023
7c8109e
Fix package-lock.json
huzaifa-99 Sep 25, 2023
2ba6260
Merge branch 'main' into 25855-get-user-location
huzaifa-99 Sep 25, 2023
74b16e2
Fix lint
huzaifa-99 Sep 25, 2023
2f0c0f0
Updated comment about ms delay for getCurrentPosition call
huzaifa-99 Sep 25, 2023
8d16400
Fix lint
huzaifa-99 Sep 25, 2023
c0d32e2
Merge branch 'main' into 25855-get-user-location
huzaifa-99 Sep 26, 2023
2f04195
Merge branch 'main' into 25855-get-user-location
huzaifa-99 Sep 28, 2023
3e8a077
Use state for location error message
huzaifa-99 Sep 28, 2023
572cd7a
Updated import
huzaifa-99 Sep 28, 2023
853f7e4
Pass default props to location error message
huzaifa-99 Sep 28, 2023
2b34ccd
Added comment about using withLocalize
huzaifa-99 Sep 28, 2023
6c505e4
Merge branch 'main' into 25855-get-user-location
huzaifa-99 Sep 29, 2023
ae8ec7a
Updated comments
huzaifa-99 Oct 2, 2023
37a47c2
Added line break before condition
huzaifa-99 Oct 2, 2023
98fcdc5
Merge branch 'main' into 25855-get-user-location
huzaifa-99 Oct 2, 2023
8a5cc0b
Merge branch 'main' into 25855-get-user-location
huzaifa-99 Oct 3, 2023
c226384
Merge branch 'main' into 25855-get-user-location
huzaifa-99 Oct 5, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ USE_WEB_PROXY=false
USE_WDYR=false
CAPTURE_METRICS=false
ONYX_METRICS=false
GOOGLE_GEOLOCATION_API_KEY=AIzaSyBqg6bMvQU7cPWDKhhzpYqJrTEnSorpiLI

EXPENSIFY_ACCOUNT_ID_ACCOUNTING=-1
EXPENSIFY_ACCOUNT_ID_ADMIN=-1
Expand Down
1 change: 1 addition & 0 deletions .env.production
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ PUSHER_APP_KEY=268df511a204fbb60884
USE_WEB_PROXY=false
ENVIRONMENT=production
SEND_CRASH_REPORTS=true
GOOGLE_GEOLOCATION_API_KEY=AIzaSyBFKujMpzExz0_z2pAGfPUwkmlaUc-uw1Q
1 change: 1 addition & 0 deletions .env.staging
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ PUSHER_APP_KEY=268df511a204fbb60884
USE_WEB_PROXY=false
ENVIRONMENT=staging
SEND_CRASH_REPORTS=true
GOOGLE_GEOLOCATION_API_KEY=AIzaSyD2T1mlByThbUN88O8OPOD8vKuMMwLD4-M
1 change: 1 addition & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS"/>

<!-- android:hardwareAccelerated is essential for Android performance: https://developer.android.com/topic/performance/hardware-accel -->
Expand Down
5 changes: 5 additions & 0 deletions desktop/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ const Localize = require('../src/libs/Localize');
const port = process.env.PORT || 8082;
const {DESKTOP_SHORTCUT_ACCELERATOR, LOCALES} = CONST;

// Setup google api key in process environment, we are setting it this way intentionally. It is required by the
// geolocation api (window.navigator.geolocation.getCurrentPosition) to work on desktop.
// Source: https://github.com/electron/electron/blob/98cd16d336f512406eee3565be1cead86514db7b/docs/api/environment-variables.md#google_api_key
process.env.GOOGLE_API_KEY = CONFIG.GOOGLE_GEOLOCATION_API_KEY;

app.setName('New Expensify');

/**
Expand Down
6 changes: 6 additions & 0 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,8 @@ PODS:
- React-Core
- react-native-flipper (0.159.0):
- React-Core
- react-native-geolocation (3.0.6):
- React-Core
- react-native-image-manipulator (1.0.5):
- React
- react-native-image-picker (5.1.0):
Expand Down Expand Up @@ -892,6 +894,7 @@ DEPENDENCIES:
- react-native-config (from `../node_modules/react-native-config`)
- react-native-document-picker (from `../node_modules/react-native-document-picker`)
- react-native-flipper (from `../node_modules/react-native-flipper`)
- "react-native-geolocation (from `../node_modules/@react-native-community/geolocation`)"
- "react-native-image-manipulator (from `../node_modules/@oguzhnatly/react-native-image-manipulator`)"
- react-native-image-picker (from `../node_modules/react-native-image-picker`)
- react-native-key-command (from `../node_modules/react-native-key-command`)
Expand Down Expand Up @@ -1065,6 +1068,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-document-picker"
react-native-flipper:
:path: "../node_modules/react-native-flipper"
react-native-geolocation:
:path: "../node_modules/@react-native-community/geolocation"
react-native-image-manipulator:
:path: "../node_modules/@oguzhnatly/react-native-image-manipulator"
react-native-image-picker:
Expand Down Expand Up @@ -1249,6 +1254,7 @@ SPEC CHECKSUMS:
react-native-config: 7cd105e71d903104e8919261480858940a6b9c0e
react-native-document-picker: f68191637788994baed5f57d12994aa32cf8bf88
react-native-flipper: dc5290261fbeeb2faec1bdc57ae6dd8d562e1de4
react-native-geolocation: 0f7fe8a4c2de477e278b0365cce27d089a8c5903
react-native-image-manipulator: c48f64221cfcd46e9eec53619c4c0374f3328a56
react-native-image-picker: c33d4e79f0a14a2b66e5065e14946ae63749660b
react-native-key-command: c2645ec01eb1fa664606c09480c05cb4220ef67b
Expand Down
9,809 changes: 9,300 additions & 509 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"@react-native-camera-roll/camera-roll": "5.4.0",
"@react-native-community/clipboard": "^1.5.1",
"@react-native-community/datetimepicker": "^3.5.2",
"@react-native-community/geolocation": "^3.0.6",
"@react-native-community/netinfo": "^9.3.10",
"@react-native-firebase/analytics": "^12.3.0",
"@react-native-firebase/app": "^12.3.0",
Expand Down Expand Up @@ -116,6 +117,7 @@
"react-map-gl": "^7.1.3",
"react-error-boundary": "^4.0.11",
"react-native": "0.72.4",
"react-native-android-location-enabler": "^1.2.2",
"react-native-blob-util": "^0.17.3",
"react-native-collapsible": "^1.6.0",
"react-native-config": "^1.4.5",
Expand Down
2 changes: 2 additions & 0 deletions src/CONFIG.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const secureExpensifyUrl = Url.addTrailingForwardSlash(get(Config, 'SECURE_EXPEN
const useNgrok = get(Config, 'USE_NGROK', 'false') === 'true';
const useWebProxy = get(Config, 'USE_WEB_PROXY', 'true') === 'true';
const expensifyComWithProxy = getPlatform() === 'web' && useWebProxy ? '/' : expensifyURL;
const googleGeolocationAPIKey = get(Config, 'GOOGLE_GEOLOCATION_API_KEY', 'AIzaSyBqg6bMvQU7cPWDKhhzpYqJrTEnSorpiLI');

// Throw errors on dev if config variables are not set correctly
if (ENVIRONMENT === CONST.ENVIRONMENT.DEV) {
Expand Down Expand Up @@ -91,4 +92,5 @@ export default {
WEB_CLIENT_ID: '921154746561-gpsoaqgqfuqrfsjdf8l7vohfkfj7b9up.apps.googleusercontent.com',
IOS_CLIENT_ID: '921154746561-s3uqn2oe4m85tufi6mqflbfbuajrm2i3.apps.googleusercontent.com',
},
GOOGLE_GEOLOCATION_API_KEY: googleGeolocationAPIKey,
} as const;
2 changes: 2 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,8 @@ const CONST = {
DEFAULT: 'default',
},

YOUR_LOCATION_TEXT: 'Your Location',

ATTACHMENT_MESSAGE_TEXT: '[Attachment]',
// This is a placeholder for attachment which is uploading
ATTACHMENT_UPLOADING_MESSAGE_HTML: 'Uploading attachment...',
Expand Down
4 changes: 2 additions & 2 deletions src/components/AddressSearch/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -344,8 +344,8 @@ function AddressSearch(props) {
props.onInputChange({street: text});
}

// If the text is empty, we set displayListViewBorder to false to prevent UI flickering
if (_.isEmpty(text)) {
// If the text is empty and we have no predefined places, we set displayListViewBorder to false to prevent UI flickering
if (_.isEmpty(text) && _.isEmpty(props.predefinedPlaces)) {
hayata-suenaga marked this conversation as resolved.
Show resolved Hide resolved
setDisplayListViewBorder(false);
}
},
Expand Down
77 changes: 77 additions & 0 deletions src/components/LocationErrorMessage/BaseLocationErrorMessage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import CONST from '../../CONST';
import colors from '../../styles/colors';
import styles from '../../styles/styles';
import Icon from '../Icon';
import * as Expensicons from '../Icon/Expensicons';
import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback';
import Text from '../Text';
import TextLink from '../TextLink';
import Tooltip from '../Tooltip';
import withLocalize, {withLocalizePropTypes} from '../withLocalize';
import * as locationErrorMessagePropTypes from './locationErrorMessagePropTypes';

const propTypes = {
/** A callback that runs when 'allow location permission' link is pressed */
onAllowLocationLinkPress: PropTypes.func.isRequired,

// eslint-disable-next-line react/forbid-foreign-prop-types
...locationErrorMessagePropTypes.propTypes,

/* Onyx Props */
...withLocalizePropTypes,
};

function BaseLocationErrorMessage({onClose, onAllowLocationLinkPress, locationErrorCode, translate}) {
if (!locationErrorCode) {
return null;
}

const isPermissionDenied = locationErrorCode === 1;

return (
<View style={[styles.dotIndicatorMessage, styles.mt4]}>
<View style={styles.offlineFeedback.errorDot}>
<Icon
src={Expensicons.DotIndicator}
fill={colors.red}
/>
</View>
<View style={styles.offlineFeedback.textContainer}>
{isPermissionDenied ? (
<Text>
<Text style={[styles.offlineFeedback.text]}>{`${translate('location.permissionDenied')} ${translate('location.please')}`}</Text>
<TextLink
onPress={onAllowLocationLinkPress}
style={styles.locationErrorLinkText}
>
{` ${translate('location.allowPermission')} `}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NAB: we should use padding instead of spaces

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces work better when text wraps the next lines as they can be collapsed.

</TextLink>
<Text style={[styles.offlineFeedback.text]}>{translate('location.tryAgain')}</Text>
</Text>
) : (
<Text style={styles.offlineFeedback.text}>{translate('location.notFound')}</Text>
)}
</View>
<View>
<Tooltip text={translate('common.close')}>
<PressableWithoutFeedback
onPress={onClose}
style={[styles.touchableButtonImage]}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.BUTTON}
accessibilityLabel={translate('common.close')}
>
<Icon src={Expensicons.Close} />
</PressableWithoutFeedback>
</Tooltip>
</View>
</View>
);
}

BaseLocationErrorMessage.displayName = 'BaseLocationErrorMessage';
BaseLocationErrorMessage.propTypes = propTypes;
BaseLocationErrorMessage.defaultProps = locationErrorMessagePropTypes.defaultProps;
export default withLocalize(BaseLocationErrorMessage);
huzaifa-99 marked this conversation as resolved.
Show resolved Hide resolved
25 changes: 25 additions & 0 deletions src/components/LocationErrorMessage/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import {Linking} from 'react-native';
import CONST from '../../CONST';
import BaseLocationErrorMessage from './BaseLocationErrorMessage';
import * as locationErrorMessagePropTypes from './locationErrorMessagePropTypes';

/** Opens expensify help site in a new browser tab */
const navigateToExpensifyHelpSite = () => {
Linking.openURL(CONST.NEWHELP_URL);
};

function LocationErrorMessage(props) {
return (
<BaseLocationErrorMessage
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
onAllowLocationLinkPress={navigateToExpensifyHelpSite}
/>
);
}

LocationErrorMessage.displayName = 'LocationErrorMessage';
LocationErrorMessage.propTypes = locationErrorMessagePropTypes.propTypes;
huzaifa-99 marked this conversation as resolved.
Show resolved Hide resolved
LocationErrorMessage.defaultProps = locationErrorMessagePropTypes.defaultProps;
export default LocationErrorMessage;
24 changes: 24 additions & 0 deletions src/components/LocationErrorMessage/index.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import {Linking} from 'react-native';
import BaseLocationErrorMessage from './BaseLocationErrorMessage';
import * as locationErrorMessagePropTypes from './locationErrorMessagePropTypes';

/** Opens app level settings from the native system settings */
const openAppSettings = () => {
Linking.openSettings();
};

function LocationErrorMessage(props) {
return (
<BaseLocationErrorMessage
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
onAllowLocationLinkPress={openAppSettings}
/>
);
}

LocationErrorMessage.displayName = 'LocationErrorMessage';
LocationErrorMessage.propTypes = locationErrorMessagePropTypes.propTypes;
huzaifa-99 marked this conversation as resolved.
Show resolved Hide resolved
LocationErrorMessage.defaultProps = locationErrorMessagePropTypes.defaultProps;
export default LocationErrorMessage;
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import PropTypes from 'prop-types';

const propTypes = {
/** A callback that runs when close icon is pressed */
onClose: PropTypes.func.isRequired,

/**
* The location error code from onyx
* - code -1 = location not supported (web only)
* - code 1 = location permission is not enabled
* - code 2 = location is unavailable or there is some connection issue
* - code 3 = location fetch timeout
*/
locationErrorCode: PropTypes.oneOf([-1, 1, 2, 3]),
};

const defaultProps = {
locationErrorCode: null,
};

export {propTypes, defaultProps};
112 changes: 112 additions & 0 deletions src/components/UserCurrentLocationButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import PropTypes from 'prop-types';
import React, {useEffect, useRef, useState} from 'react';
import {Text} from 'react-native';
import getCurrentPosition from '../libs/getCurrentPosition';
import styles from '../styles/styles';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
import LocationErrorMessage from './LocationErrorMessage';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
import colors from '../styles/colors';
import PressableWithFeedback from './Pressable/PressableWithFeedback';

const propTypes = {
/** Callback that runs when location data is fetched */
onLocationFetched: PropTypes.func.isRequired,

/** Callback that runs when fetching location has errors */
onLocationError: PropTypes.func,

/** Callback that runs when location button is clicked */
onClick: PropTypes.func,

/** Boolean to indicate if the button is clickable */
isDisabled: PropTypes.bool,

...withLocalizePropTypes,
huzaifa-99 marked this conversation as resolved.
Show resolved Hide resolved
};

const defaultProps = {
isDisabled: false,
onLocationError: () => {},
onClick: () => {},
};

function UserCurrentLocationButton({onLocationFetched, onLocationError, onClick, isDisabled, translate}) {
const isFetchingLocation = useRef(false);
const shouldTriggerCallbacks = useRef(true);
const [locationErrorCode, setLocationErrorCode] = useState(null);

/** Gets the user's current location and registers success/error callbacks */
const getUserLocation = () => {
if (isFetchingLocation.current) {
return;
}

isFetchingLocation.current = true;

onClick();

getCurrentPosition(
hayata-suenaga marked this conversation as resolved.
Show resolved Hide resolved
(successData) => {
isFetchingLocation.current = false;
if (!shouldTriggerCallbacks.current) {
return;
}

setLocationErrorCode(null);
onLocationFetched(successData);
},
(errorData) => {
isFetchingLocation.current = false;
if (!shouldTriggerCallbacks.current) {
return;
}

setLocationErrorCode(errorData.code);
onLocationError(errorData);
},
{
maximumAge: 0, // No cache, always get fresh location info
timeout: 5000,
},
);
};

// eslint-disable-next-line arrow-body-style
useEffect(() => {
return () => {
// If the component unmounts we don't want any of the callback for geolocation to run.
shouldTriggerCallbacks.current = false;
};
}, []);

return (
<>
<PressableWithFeedback
style={[styles.flexRow, styles.mt4, styles.alignSelfStart, isDisabled && styles.buttonOpacityDisabled]}
onPress={getUserLocation}
accessibilityLabel={translate('location.useCurrent')}
disabled={isDisabled}
>
<Icon
src={Expensicons.Location}
fill={colors.green}
/>
<Text style={[styles.textLabel, styles.mh2, isDisabled && styles.userSelectNone]}>{translate('location.useCurrent')}</Text>
</PressableWithFeedback>
<LocationErrorMessage
onClose={() => setLocationErrorCode(null)}
locationErrorCode={locationErrorCode}
/>
</>
);
}

UserCurrentLocationButton.displayName = 'UserCurrentLocationButton';
UserCurrentLocationButton.propTypes = propTypes;
UserCurrentLocationButton.defaultProps = defaultProps;

// This components gets used inside <Form/>, we are using an HOC (withLocalize) as function components with
// hooks give hook errors when nested inside <Form/>.
export default withLocalize(UserCurrentLocationButton);
huzaifa-99 marked this conversation as resolved.
Show resolved Hide resolved
Loading
Loading