From f0a1716b32bfac4b295f6f407f211f6aba8e371d Mon Sep 17 00:00:00 2001 From: Haraman Johal Date: Sat, 10 Oct 2020 10:54:08 +0100 Subject: [PATCH] feat: Use last known location if GPS fails to sync (#752) * Save last known location * save location on manual selection too * use saved location if available * yarn lint * use fp-ts idiomatic code and handle saving inside a useEffect hook * yarn lint * use a const variable rather than string literal --- App/stores/location.tsx | 46 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/App/stores/location.tsx b/App/stores/location.tsx index c41dde27..044407ec 100644 --- a/App/stores/location.tsx +++ b/App/stores/location.tsx @@ -19,8 +19,9 @@ import { pipe } from 'fp-ts/lib/pipeable'; import * as T from 'fp-ts/lib/Task'; import * as TE from 'fp-ts/lib/TaskEither'; import React, { createContext, useContext, useEffect, useState } from 'react'; +import { AsyncStorage } from 'react-native'; -import { sideEffect } from '../util/fp'; +import { promiseToTE, sideEffect } from '../util/fp'; import { noop } from '@shootismoke/ui'; import { sentryError } from '../util/sentry'; import { ErrorContext } from './error'; @@ -30,6 +31,8 @@ import { Location, } from './util/fetchGpsPosition'; +const LAST_KNOWN_LOCATION_KEY = 'LAST_KNOWN_LOCATION' + const DEFAULT_LAT_LNG: LatLng = { latitude: 0, longitude: 0, @@ -88,6 +91,40 @@ export function LocationContextProvider({ ) ) ), + TE.orElse((err) => + pipe( + promiseToTE( + () => AsyncStorage.getItem('LAST_KNOWN_LOCATION'), + 'LocationContext' + ), + TE.chain((locationString) => { + // Skip parsing if AsyncStorage is empty. + if (!locationString) { + return TE.left( + new Error( + 'AsyncStorage does not contain LAST_KNOWN_LOCATION' + ) + ); + } + + const parsedLocation = JSON.parse( + locationString + ) as Location; + + // Make sure parsedLocation is well-formed. + return parsedLocation.latitude && + parsedLocation.longitude + ? TE.right(parsedLocation) + : TE.left( + new Error( + 'AsyncStorage has ill-formatted LAST_KNOWN_LOCATION' + ) + ); + }), + // Show the initial error from fetchGpsPosition. + TE.mapLeft(() => err) + ) + ), TE.fold( (err) => { setError(err); @@ -109,6 +146,13 @@ export function LocationContextProvider({ )().catch(sentryError('LocationContextProvider')); }, []); // eslint-disable-line react-hooks/exhaustive-deps + useEffect(() => { + AsyncStorage.setItem( + LAST_KNOWN_LOCATION_KEY, + JSON.stringify(currentLocation) + ).catch(sentryError('LocationContextProvider')); + }, [currentLocation]); + return (