Skip to content

Commit

Permalink
Added getCurrentPosition util
Browse files Browse the repository at this point in the history
  • Loading branch information
huzaifa-99 committed Sep 1, 2023
1 parent 57603a0 commit cd8cb9b
Show file tree
Hide file tree
Showing 12 changed files with 9,464 additions and 401 deletions.
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
10 changes: 8 additions & 2 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 All @@ -591,7 +593,7 @@ PODS:
- React-Core
- react-native-pager-view (6.2.0):
- React-Core
- react-native-pdf (6.6.2):
- react-native-pdf (6.7.1):
- React-Core
- react-native-performance (4.0.0):
- React-Core
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,12 +1254,13 @@ 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
react-native-netinfo: ccbe1085dffd16592791d550189772e13bf479e2
react-native-pager-view: 0ccb8bf60e2ebd38b1f3669fa3650ecce81db2df
react-native-pdf: 33c622cbdf776a649929e8b9d1ce2d313347c4fa
react-native-pdf: 7c0e91ada997bac8bac3bb5bea5b6b81f5a3caae
react-native-performance: 224bd53e6a835fda4353302cf891d088a0af7406
react-native-plaid-link-sdk: 9eb0f71dad94b3bdde649c7a384cba93024af46c
react-native-quick-sqlite: bcc7a7a250a40222f18913a97cd356bf82d0a6c4
Expand Down
9,658 changes: 9,259 additions & 399 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 @@ -64,6 +64,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 @@ -115,6 +116,7 @@
"react-native-document-picker": "^8.0.0",
"react-native-fast-image": "^8.6.3",
"react-native-fs": "^2.20.0",
"react-native-geolocation": "^1.0.0",
"react-native-gesture-handler": "2.12.0",
"react-native-google-places-autocomplete": "git+https://github.com/Expensify/react-native-google-places-autocomplete.git#ee87343c3e827ff7818abc71b6bb04fcc1f120e0",
"react-native-haptic-feedback": "^1.13.0",
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;
100 changes: 100 additions & 0 deletions src/libs/getCurrentPosition/getCurrentPosition.desktop.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import CONFIG from '../../CONFIG';
import {GetCurrentPosition, GeolocationErrorCode} from './getCurrentPosition.types';

type GoogleAPIsGeoLocateResponse = {
location: {
lat: number;
lng: number;
};
accuracy: number;
};

const BASE_URL = 'https://www.googleapis.com/geolocation/v1/geolocate';

// Api request config
const requestConfig: RequestInit = {
method: 'POST',
};

const getCurrentPosition: GetCurrentPosition = (
success,
error,
options, // We will ignore options.maximumAge and options.enableHighAccuracy since cant pass it to geolocate api directly
) => {
// Emulate the timeout param with an abort signal
let timeoutID: NodeJS.Timeout;
if (options?.timeout) {
const abortController = new AbortController();
timeoutID = setTimeout(() => {
abortController.abort();
}, options.timeout);
requestConfig.signal = abortController.signal;
}

// Gets current location from google geolocation api
fetch(`${BASE_URL}?key=${CONFIG.GOOGLE_GEOLOCATION_API_KEY}`, requestConfig)
.then((response) => {
if (!response.ok) {
throw new Error(response.statusText);
}

return response.json();
})
.then((response: GoogleAPIsGeoLocateResponse) => {
// Transform response to match with the window.navigator.geolocation.getCurrentPosition response
const transformedResponse = {
coords: {
latitude: response.location.lat,
longitude: response.location.lng,
accuracy: response.accuracy,
// Return null for these keys as we don't get them in response when api is directly called
altitude: null,
altitudeAccuracy: null,
heading: null,
speed: null,
},
timestamp: Date.now(), // The api call doesn't return timestamp directly, so we emulate ourselves
};

success(transformedResponse);
})
.catch((apiError) => {
// The base error object when api call fails
const baseErrorObject = {
// Since we are making a direct api call, we won't get permission denied error code
PERMISSION_DENIED: GeolocationErrorCode.PERMISSION_DENIED,
POSITION_UNAVAILABLE: GeolocationErrorCode.POSITION_UNAVAILABLE,
TIMEOUT: GeolocationErrorCode.TIMEOUT,
NOT_SUPPORTED: GeolocationErrorCode.NOT_SUPPORTED,
};

// Return timeout error on abort
if (apiError instanceof Error && apiError.message === 'The user aborted a request.') {
error({
...baseErrorObject,
code: GeolocationErrorCode.TIMEOUT,
// Adds a generic message for desktop, when timeout occurs
message: 'timeout',
});
return;
}

error({
...baseErrorObject,
code: GeolocationErrorCode.POSITION_UNAVAILABLE,
// Adding a generic message for desktop, position unavailable can mean 'no internet'
// or some other position related issues on api call failure (excluding timeout)
message: 'position unavailable',
});
})
.finally(() => {
if (!timeoutID) {
return;
}

// Clear any leftover timeouts
clearTimeout(timeoutID);
});
};

export default getCurrentPosition;
14 changes: 14 additions & 0 deletions src/libs/getCurrentPosition/getCurrentPosition.native.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Geolocation from '@react-native-community/geolocation';
import {GetCurrentPosition} from './getCurrentPosition.types';

Geolocation.setRNConfiguration({
skipPermissionRequests: false,
authorizationLevel: 'whenInUse',
locationProvider: 'auto',
});

const getCurrentPosition: GetCurrentPosition = (success, error, config) => {
Geolocation.getCurrentPosition(success, error, config);
};

export default getCurrentPosition;
19 changes: 19 additions & 0 deletions src/libs/getCurrentPosition/getCurrentPosition.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {GeolocationErrorCode, GetCurrentPosition} from './getCurrentPosition.types';

const getCurrentPosition: GetCurrentPosition = (success, error, options) => {
if (typeof navigator === 'undefined' || !('geolocation' in navigator)) {
error({
code: GeolocationErrorCode.NOT_SUPPORTED,
message: 'Geolocation is not supported by this environment.',
PERMISSION_DENIED: GeolocationErrorCode.PERMISSION_DENIED,
POSITION_UNAVAILABLE: GeolocationErrorCode.POSITION_UNAVAILABLE,
TIMEOUT: GeolocationErrorCode.TIMEOUT,
NOT_SUPPORTED: GeolocationErrorCode.NOT_SUPPORTED,
});
return;
}

navigator.geolocation.getCurrentPosition(success, error, options);
};

export default getCurrentPosition;
54 changes: 54 additions & 0 deletions src/libs/getCurrentPosition/getCurrentPosition.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
type GeolocationSuccessCallback = (position: {
coords: {
latitude: number;
longitude: number;
altitude: number | null;
accuracy: number;
altitudeAccuracy: number | null;
heading: number | null;
speed: number | null;
};
timestamp: number;
}) => void;

type GeolocationErrorCallback = (error: {
code: (typeof GeolocationErrorCode)[keyof typeof GeolocationErrorCode];
message: string;
PERMISSION_DENIED: typeof GeolocationErrorCode.PERMISSION_DENIED;
POSITION_UNAVAILABLE: typeof GeolocationErrorCode.POSITION_UNAVAILABLE;
TIMEOUT: typeof GeolocationErrorCode.TIMEOUT;

/* Web only */
NOT_SUPPORTED?: typeof GeolocationErrorCode.NOT_SUPPORTED;
}) => void;

const GeolocationErrorCode = {
PERMISSION_DENIED: 1,
POSITION_UNAVAILABLE: 2,
TIMEOUT: 3,
NOT_SUPPORTED: -1,
};

type GeolocationOptions = {
timeout?: number;
maximumAge?: number;
enableHighAccuracy?: boolean;

/** Native only */
distanceFilter?: number;

/** Native only */
useSignificantChanges?: boolean;

/** Native only */
interval?: number;

/** Native only */
fastestInterval?: number;
};

type GetCurrentPosition = (success: GeolocationSuccessCallback, error: GeolocationErrorCallback, options?: GeolocationOptions) => void;

export {GeolocationErrorCode};

export type {GeolocationSuccessCallback, GeolocationErrorCallback, GeolocationOptions, GetCurrentPosition};
3 changes: 3 additions & 0 deletions src/libs/getCurrentPosition/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import getCurrentPosition from './getCurrentPosition';

export default getCurrentPosition;

0 comments on commit cd8cb9b

Please sign in to comment.