location capture || Aman Singh (#129)

* location capture

* askForPermission function else part corrected

* askForPermission function else part corrected

* added granted from Enum

* Removed extra import came form merge conflict
This commit is contained in:
Aman Singh
2023-03-03 10:02:54 +05:30
committed by GitHub Enterprise
parent d82c740da4
commit d4b8e018e5
8 changed files with 129 additions and 32 deletions

39
App.tsx
View File

@@ -1,5 +1,5 @@
import React from 'react';
import { KeyboardAvoidingView,LogBox } from 'react-native';
import { LogBox, PermissionsAndroid, Platform , KeyboardAvoidingView, PermissionStatus} from 'react-native';
import {Provider} from 'react-redux';
import store, {persistor} from './src/store/store';
import {PersistGate} from 'redux-persist/integration/react';
@@ -8,7 +8,7 @@ import {NavigationContainer} from '@react-navigation/native';
import {navigationRef} from './src/components/utlis/navigationUtlis';
import FullScreenLoader from './RN-UI-LIB/src/components/FullScreenLoader';
import ProtectedRouter from './ProtectedRouter';
import { toastConfigs, ToastContainer } from './RN-UI-LIB/src/components/toast';
import { toast, toastConfigs, ToastContainer } from './RN-UI-LIB/src/components/toast';
import ErrorBoundary from './src/common/ErrorBoundary';
@@ -20,6 +20,8 @@ import { COLORS } from './RN-UI-LIB/src/styles/colors';
import codePush from 'react-native-code-push';
import { ENV } from './src/constants/config';
import { mockApiServer } from './src/mock-api/server';
import Text from './RN-UI-LIB/src/components/Text';
import { PermissionStatusEnum } from './src/services/geolocation.service';
Sentry.init({ dsn: SENTRY_DSN });
if (ENV !== 'prod') {
@@ -28,8 +30,38 @@ if (ENV !== 'prod') {
LogBox.ignoreAllLogs();
const askForPermissions = (setPermissions:React.Dispatch<React.SetStateAction<boolean>> ) => {
if (Platform.OS === 'android') {
PermissionsAndroid.requestMultiple(
[PermissionsAndroid.PERMISSIONS.CAMERA,
PermissionsAndroid.PERMISSIONS.READ_CONTACTS,
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION,
PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE,
PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE]
).then((result) => {
if (result['android.permission.ACCESS_COARSE_LOCATION']
&& result['android.permission.CAMERA']
&& result['android.permission.READ_CONTACTS']
&& result['android.permission.ACCESS_FINE_LOCATION']
&& result['android.permission.READ_EXTERNAL_STORAGE']
&& result['android.permission.WRITE_EXTERNAL_STORAGE'] === PermissionStatusEnum.GRANTED) {
setPermissions(true)
} else {
toast({type:'info', text1:'Please Go into Settings -> Applications -> Field App -> Permissions and Allow permissions to continue'});
setPermissions(false)
}
});
}
}
const App = () => {
useNativeButtons();
const [permissions, setPermissions] = React.useState(true);
React.useEffect(()=>{
askForPermissions(setPermissions);
}, [])
return (
<Provider store={store}>
<PersistGate
@@ -38,7 +70,8 @@ const App = () => {
<NavigationContainer ref={navigationRef}>
<StatusBar backgroundColor={COLORS.BACKGROUND.INDIGO_DARK} />
<ErrorBoundary>
<ProtectedRouter />
{/* TODO: ASK Adhya for designs its been more than 1 month */}
{permissions ? <ProtectedRouter /> : <Text>Please grant Permisisons</Text>}
</ErrorBoundary>
</NavigationContainer>
{

View File

@@ -43,6 +43,7 @@
"react-native": "0.70.6",
"react-native-code-push": "7.1.0",
"react-native-device-info": "10.3.0",
"react-native-geolocation-service": "5.3.1",
"react-native-image-picker": "4.10.2",
"react-native-pager-view": "6.1.2",
"react-native-permissions": "3.6.1",

View File

@@ -4,11 +4,10 @@ import {
ScrollView,
StyleSheet,
TouchableHighlight,
View,
View
} from 'react-native';
import Geolocation from 'react-native-geolocation-service';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useNavigationState } from '@react-navigation/native';
import { useDispatch } from 'react-redux';
import Button from '../../../RN-UI-LIB/src/components/Button';
import Heading from '../../../RN-UI-LIB/src/components/Heading';
import Text from '../../../RN-UI-LIB/src/components/Text';
@@ -16,22 +15,24 @@ import ArrowSolidIcon from '../../../RN-UI-LIB/src/Icons/ArrowSolidIcon';
import CloseIcon from '../../../RN-UI-LIB/src/Icons/CloseIcon';
import { GenericStyles, getShadowStyle } from '../../../RN-UI-LIB/src/styles';
import { COLORS } from '../../../RN-UI-LIB/src/styles/colors';
import { useAppDispatch, useAppSelector } from '../../hooks';
import { getUpdatedAVCaseDetail, getUpdatedCollectionCaseDetail, updateCaseDetail } from '../../reducer/allCasesSlice';
import { deleteInteraction, deleteJourney, updateInteraction, } from '../../reducer/caseReducer';
import { getTemplateRoute, getWidgetNameFromRoute, goBack, navigateToScreen, } from '../utlis/navigationUtlis';
import RenderQuestion from './RenderQuestion';
import Submit from './Submit';
import { addClickstreamEvent } from '../../services/clickstreamEventService';
import { CLICKSTREAM_EVENT_NAMES } from '../../common/Constants';
import Layout from '../../screens/layout/Layout';
import { getNextJourneyActions, getNextWidget } from "./services/forms.service";
import { FormTemplateV1 } from "../../types/template.types";
import { CaseAllocationType } from "../../screens/allCases/interface";
import useIsOnline from '../../hooks/useIsOnline';
import { getUnSyncedCase } from '../../screens/caseDetails/interactionsHandler';
import { getTransformedAvCase, getTransformedCollectionCaseItem } from '../../services/casePayload.transformer';
import { syncCaseDetail } from '../../action/dataActions';
import { CLICKSTREAM_EVENT_NAMES } from '../../common/Constants';
import { useAppDispatch, useAppSelector } from '../../hooks';
import useIsOnline from '../../hooks/useIsOnline';
import { getUpdatedAVCaseDetail, getUpdatedCollectionCaseDetail, updateCaseDetail } from '../../reducer/allCasesSlice';
import { deleteInteraction, deleteJourney, updateInteraction } from '../../reducer/caseReducer';
import { CaseAllocationType } from "../../screens/allCases/interface";
import { getUnSyncedCase } from '../../screens/caseDetails/interactionsHandler';
import Layout from '../../screens/layout/Layout';
import { getTransformedAvCase, getTransformedCollectionCaseItem } from '../../services/casePayload.transformer';
import { addClickstreamEvent } from '../../services/clickstreamEventService';
import { FormTemplateV1 } from "../../types/template.types";
import { logError } from '../utlis/errorUtils';
import { getTemplateRoute, getWidgetNameFromRoute, goBack, navigateToScreen } from '../utlis/navigationUtlis';
import RenderQuestion from './RenderQuestion';
import { getNextJourneyActions, getNextWidget } from "./services/forms.service";
import { requestLocationPermission } from './services/geoLocation.service';
import Submit from './Submit';
import { toast } from '../../../RN-UI-LIB/src/components/toast';
interface IWidget {
@@ -134,11 +135,27 @@ const Widget: React.FC<IWidget> = props => {
);
}
const handleSubmitJourney = async(data: any) => {
const submitJourneyWithGeoLocation = (data: any) => {
addClickstreamEvent(
CLICKSTREAM_EVENT_NAMES.AV_FORM_SUBMIT_BUTTON_CLICKED,
{ caseId, journeyId: journey, widgetId: name },
);
const isLocationOn = requestLocationPermission();
if(!isLocationOn) return;
Geolocation.getCurrentPosition(
position => {
return handleSubmitJourney(data, position.coords);
},
error => {
logError((error as any), "Unable to get location")
return;
},
{ enableHighAccuracy: true, timeout: 15e3, maximumAge: 1e4 },
);
}
const handleSubmitJourney = async(data: any, coords: Geolocation.GeoCoordinates) => {
dispatch(
updateInteraction({
caseId,
@@ -146,9 +163,9 @@ const Widget: React.FC<IWidget> = props => {
widgetId: name,
answer: data,
}),
);
);
if (caseType === CaseAllocationType.COLLECTION_CASE) {
const updatedCase = getUpdatedCollectionCaseDetail({caseData, answer: data});
const updatedCase = getUpdatedCollectionCaseDetail({caseData, answer: data, coords});
if(isOnline) {
setShowSubmitLoader(true);
const unsyncedCase = getUnSyncedCase(updatedCase);
@@ -196,6 +213,7 @@ const Widget: React.FC<IWidget> = props => {
caseData,
nextActions,
templateId,
coords
});
if(isOnline) {
@@ -373,7 +391,7 @@ const Widget: React.FC<IWidget> = props => {
showLoader={isLeaf && showSubmitLoader}
onPress={
isLeaf
? handleSubmit(handleSubmitJourney, onError)
? handleSubmit(submitJourneyWithGeoLocation, onError)
: handleSubmit(onSubmit, onError)
}
rightIcon={

View File

@@ -0,0 +1,19 @@
import { PermissionsAndroid } from "react-native";
export const requestLocationPermission = async () => {
try {
const granted = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
{
title: 'Geolocation Permission',
message: 'Can we access your location?',
buttonNeutral: 'Ask Me Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
},
);
return granted === 'granted';
} catch (err) {
return false;
}
};

View File

@@ -66,7 +66,24 @@ const initialState: IAllCasesSlice = {
visitPlansUpdating: false,
};
export const getUpdatedCollectionCaseDetail = ({caseData, answer}: any) => {
const getPinnedListDetails = (casesList: ICaseItem[]) => {
let maxPinnedRank = 0;
const pinnedList: ICaseItem[] = [];
casesList.forEach(caseItem => {
const { pinRank } = caseItem;
if (pinRank === null || pinRank === undefined) {
return;
}
pinnedList.push(caseItem);
if (pinRank > maxPinnedRank) {
maxPinnedRank = pinRank;
}
});
return { pinnedList, maxPinnedRank };
};
export const getUpdatedCollectionCaseDetail = ({caseData, answer, coords}: any) => {
const updatedValue = { ...caseData };
updatedValue.isSynced = false;
updatedValue.isApiCalled = false;
@@ -83,10 +100,11 @@ export const getUpdatedCollectionCaseDetail = ({caseData, answer}: any) => {
allocationReferenceId: answer.allocationReferenceId,
};
updatedValue.answer = newAnswer;
updatedValue.coords = coords;
return updatedValue;
};
export const getUpdatedAVCaseDetail = ({journeyId, answer, caseData, nextActions, templateId}: any) => {
export const getUpdatedAVCaseDetail = ({journeyId, answer, caseData, nextActions, templateId, coords}: any) => {
const updatedValue = { ...caseData };
updatedValue.isSynced = false;
updatedValue.isApiCalled = false;
@@ -170,6 +188,7 @@ export const getUpdatedAVCaseDetail = ({journeyId, answer, caseData, nextActions
updatedValue.caseStatus = CaseStatuses.CLOSED;
updatedValue.caseVerdict = caseVerdict.EXHAUSTED;
}
updatedValue.coords = coords;
return updatedValue;
};

View File

@@ -2,6 +2,7 @@ import { CaseDetail } from './../screens/caseDetails/interface';
import { AnswerType } from '../components/form/interface';
import OfflineImageDAO from '../wmDB/dao/OfflineImageDAO';
import { CaseAllocationType } from '../screens/allCases/interface';
import Geolocation from 'react-native-geolocation-service';
interface QuestionContext {
answer: string;
@@ -129,10 +130,10 @@ export const getImageFromOfflineDb = async (imageId: string) => {
export interface IGetTransformedCaseItem extends CaseDetail {
answer: any;
caseId: string;
coords: Geolocation.GeoCoordinates
}
export const getTransformedCollectionCaseItem = async (
caseItem: IGetTransformedCaseItem,
) => {
caseItem: IGetTransformedCaseItem) => {
let cloneCaseItem = { ...caseItem };
let answerContextArray = await extractQuestionContext(
cloneCaseItem?.answer,
@@ -140,13 +141,13 @@ export const getTransformedCollectionCaseItem = async (
let data = {
caseReferenceId: caseItem.caseReferenceId,
answers: answerContextArray,
location: undefined,
location: cloneCaseItem?.coords,
};
return { caseType: caseItem.caseType, data };
};
export const getTransformedAvCase = async(caseItem: IGetTransformedCaseItem, templateId: string) => {
const { caseType, allocationReferenceId, caseId } = caseItem;
const { caseType, allocationReferenceId, caseId, coords } = caseItem;
const transformedAvCase: any = {
caseType: caseType || CaseAllocationType.ADDRESS_VERIFICATION_CASE,
data: {
@@ -155,6 +156,7 @@ export const getTransformedAvCase = async(caseItem: IGetTransformedCaseItem, tem
caseReferenceId: caseId,
taskStatuses: {},
answers: [],
location: coords,
}
}
const taskContext = caseItem?.context?.taskContext;

View File

@@ -6,7 +6,7 @@ import { logError } from '../components/utlis/errorUtils';
const { RNFusedLocation } = NativeModules;
enum PermissionStatusEnum {
export enum PermissionStatusEnum {
GRANTED = 'granted',
DENIED = 'denied',
NEVER_ASK = 'never_ask_again'

View File

@@ -7255,6 +7255,11 @@ react-native-device-info@10.3.0:
resolved "https://registry.yarnpkg.com/react-native-device-info/-/react-native-device-info-10.3.0.tgz#6bab64d84d3415dd00cc446c73ec5e2e61fddbe7"
integrity sha512-/ziZN1sA1REbJTv5mQZ4tXggcTvSbct+u5kCaze8BmN//lbxcTvWsU6NQd4IihLt89VkbX+14IGc9sVApSxd/w==
react-native-geolocation-service@5.3.1:
version "5.3.1"
resolved "https://registry.yarnpkg.com/react-native-geolocation-service/-/react-native-geolocation-service-5.3.1.tgz#4ce1017789da6fdfcf7576eb6f59435622af4289"
integrity sha512-LTXPtPNmrdhx+yeWG47sAaCgQc3nG1z+HLLHlhK/5YfOgfLcAb9HAkhREPjQKPZOUx8pKZMIpdGFUGfJYtimXQ==
react-native-gradle-plugin@^0.70.3:
version "0.70.3"
resolved "https://registry.yarnpkg.com/react-native-gradle-plugin/-/react-native-gradle-plugin-0.70.3.tgz#cbcf0619cbfbddaa9128701aa2d7b4145f9c4fc8"