TP-1 | asdf (#226)

This commit is contained in:
Ishan Srivastava
2023-04-12 12:45:59 +05:30
committed by GitHub Enterprise
parent 8222ae6873
commit 40fa19a7c9
11 changed files with 87 additions and 52 deletions

View File

@@ -1,4 +1,5 @@
export const BASE_AV_APP_URL = 'https://longhorn.navi.com/field-app';
export const SENTRY_DSN = 'https://877396e88a2b4f78b911016c64f9121a@glitchtip.cmd.navi-tech.in/155';
// sentry.io
export const SENTRY_DSN = 'https://e979a70a4d8649ca9f02583816505788@o4504994571157504.ingest.sentry.io/4504994577907712';
export const JANUS_SERVICE_URL = 'https://longhorn.navi.com/api/events/json';
export const ENV = 'prod';

View File

@@ -22,6 +22,11 @@ import {setFilters} from "../reducer/filtersSlice";
import { toast } from "../../RN-UI-LIB/src/components/toast";
import { ToastMessages } from '../screens/allCases/constants';
let _signedApiCallBucket: { req: any, added_At: number }[] = []
let _signedApiCallBucketTimer: number = 0;
const SIGNED_API_BUCKET_SIZE = 10
const SIGNED_API_BUCKET_TIMEOUT = 7*1000;
export const postPinnedList =
(pinnedCases: IPinnedCasesPayload[], updatedCaseList: ICaseItem[], type: string) =>
(dispatch: AppDispatch) => {
@@ -142,23 +147,56 @@ interface ISignedRequestItem {
}
export type ISignedRequest = ISignedRequestItem[]
export const getSignedApi = async (signedRequestPayload: ISignedRequest): Promise<{imageUrl: string}> => {
const url = getApiUrl(ApiKeys.GET_SIGNED_URL);
const response = await axiosInstance
.post(url, signedRequestPayload, {
headers: {
donotHandleError: true,
},
})
.then(response => {
if (response?.data) {
return { imageUrl: (Object.values(response?.data)?.[0] as string) ?? '' };
}
return {imageUrl: ''};
})
.catch(err => {
logError(err);
return {imageUrl: ''};
});
return response;
// TODO : make a immediate resolve provision as well, that bypassses batching.
export const getSignedApi = async (signedRequestPayload: ISignedRequest, shouldBatch = false): Promise<{ imageUrl: string }> => {
return new Promise((res) => {
if(shouldBatch){
batchSignedApiRequest(signedRequestPayload, (results: any) => {
res({imageUrl: results?.[signedRequestPayload[0].documentReferenceId] || ''})
})
}
else {
makeBulkSignedApiRequest(signedRequestPayload, (results: any) => {
res({imageUrl: results?.[signedRequestPayload[0].documentReferenceId] || ''})
})
}
})
};
async function batchSignedApiRequest(payload: ISignedRequestItem[], callback: any) {
payload.forEach(item => {
_signedApiCallBucket.push({req: item, added_At: Date.now()})
})
if (_signedApiCallBucket.length > SIGNED_API_BUCKET_SIZE) {
await makeBulkSignedApiRequest(_signedApiCallBucket.map(a => a.req), callback);
return
}
else if (!_signedApiCallBucketTimer){
_signedApiCallBucketTimer = setTimeout(async () => {
await makeBulkSignedApiRequest(_signedApiCallBucket.map(a => a.req), callback);
}, SIGNED_API_BUCKET_TIMEOUT)
}
}
async function makeBulkSignedApiRequest(payload: ISignedRequestItem[], callback: any){
const url = getApiUrl(ApiKeys.GET_SIGNED_URL);
_signedApiCallBucket=[];
await axiosInstance
.post(url, payload, {
headers: {
donotHandleError: true,
},
})
.then(response => {
callback(response?.data)
})
.catch(err => {
logError(err);
callback()
});
clearTimeout(_signedApiCallBucketTimer);
_signedApiCallBucketTimer = 0;
}

View File

@@ -32,7 +32,6 @@ export enum ApiKeys {
NOTIFICATION_ACTION,
NOTIFICATION_DELIVERED,
SEND_LOCATION,
TRACE_ERROR
}
export const API_URLS: Record<ApiKeys, string> = {} as Record<ApiKeys, string>;
@@ -56,7 +55,6 @@ API_URLS[ApiKeys.NOTIFICATIONS] = '/notification/fetch';
API_URLS[ApiKeys.NOTIFICATION_ACTION] = '/notification/action';
API_URLS[ApiKeys.NOTIFICATION_DELIVERED] = '/notification/delivered';
API_URLS[ApiKeys.SEND_LOCATION] = '/geolocations/agents';
API_URLS[ApiKeys.TRACE_ERROR] = '/trace/error';
export const API_STATUS_CODE = {
OK: 200,
@@ -154,7 +152,6 @@ axiosInstance.interceptors.response.use(
},
error => {
const {config, response} = error;
axiosInstance.post(getApiUrl(ApiKeys.TRACE_ERROR), {msg:JSON.stringify(error || {}), agentReferenceId: GLOBAL.AGENT_ID, deviceId: `${response?.status} ${GLOBAL.SESSION_TOKEN}`}).then(res => console.log("res::", res)).catch(e=>console.error("error::", e))
logError(error as Error, config?.baseURL+config?.url);
if(config.headers.donotHandleError) {
return;

View File

@@ -20,7 +20,7 @@ const getInitialDocumentObj = (caseDetails: CaseDetail) => (documentTypeList: DO
{ ...acc, [curr]: getDocumentUrlFromCaseDetails(caseDetails, curr) }), {} as TDocumentObj);
};
const useFetchDocument = (caseDetails: CaseDetail, documentTypeList: DOCUMENT_TYPE[], enableCaching = true) => {
const useFetchDocument = (caseDetails: CaseDetail, documentTypeList: DOCUMENT_TYPE[], enableCaching = true, enableBatching = false) => {
const getInitialDocumentObjFn = getInitialDocumentObj(caseDetails);
@@ -94,7 +94,7 @@ const useFetchDocument = (caseDetails: CaseDetail, documentTypeList: DOCUMENT_TY
];
setLoading(true);
const response = await getSignedApi(signedRequestPayload);
const response = await getSignedApi(signedRequestPayload, enableBatching);
setLoading(false);
const url = response?.imageUrl;

View File

@@ -160,7 +160,6 @@ const useFirestoreUpdates = () => {
})
.catch(error => {
logError(error as Error, 'Error in signInUserToFirebase');
axiosInstance.post(getApiUrl(ApiKeys.TRACE_ERROR), {msg:JSON.stringify(error || {}), agentReferenceId: GLOBAL.AGENT_ID, deviceId: `firestore ${GLOBAL.SESSION_TOKEN}`}).then(res => console.log("res::", res)).catch(e=>console.error("error::", e))
setGlobalUserData({token: '', agentId:'', deviceId:''});
dispatch(
setAuthData({

View File

@@ -9,14 +9,17 @@ import { CaseTypes, ICaseItem } from './interface';
import ListItem from './ListItem';
import Button from '../../../RN-UI-LIB/src/components/Button';
import { navigateToScreen } from '../../components/utlis/navigationUtlis';
import { CaseDetail } from "../caseDetails/interface";
interface ICaseItemProps extends ViewProps {
data: ListRenderItemInfo<ICaseItem>;
entireCaseData:CaseDetail;
handleSearchChange: (value: string) => void;
}
const CaseItem: React.FC<ICaseItemProps> = ({
data: { item: caseData },
entireCaseData,
handleSearchChange,
...restProps
}) => {
@@ -33,7 +36,7 @@ const CaseItem: React.FC<ICaseItemProps> = ({
default:
return (
<View {...restProps}>
<ListItem caseData={caseData} />
<ListItem caseData={caseData} entireCaseObject={entireCaseData} shouldBatchAvatar={true} />
</View>
);
}

View File

@@ -13,6 +13,7 @@ interface ICaseItemAvatar {
size?: number;
showBorder?: boolean;
enableRetry?: boolean;
shouldBatchAvatar?: boolean;
}
const RELATIVE_ASYNC_ICON_RIGHT_POSITION = -5;
@@ -24,6 +25,7 @@ const CaseItemAvatar: React.FC<ICaseItemAvatar> = ({
size = AVATAR_SIZE,
showBorder = false,
enableRetry = true,
shouldBatchAvatar = false
}) => {
const referenceId = caseData?.caseReferenceId || caseData?.id;
const { caseDetails, pinnedList } = useAppSelector(
@@ -43,7 +45,7 @@ const CaseItemAvatar: React.FC<ICaseItemAvatar> = ({
}
const isSynced = caseDetails?.isSynced;
const { documentObj, setRetryForUnsignedDocuments, loading } = useFetchDocument(caseDetails, requiredDocumentTypeList)
const { documentObj, setRetryForUnsignedDocuments, loading } = useFetchDocument(caseDetails, requiredDocumentTypeList, true, shouldBatchAvatar)
const onError = async () => {

View File

@@ -149,7 +149,7 @@ const CasesList: React.FC<ICasesList> = ({ casesList = [], isVisitPlan }) => {
CLICKSTREAM_EVENT_NAMES.AV_CASE_LIST_SEARCH_QUERY_CHANGED,
{ query },
);
},500), []);
},200),[]);
const handleListScroll = (
event: NativeSyntheticEvent<NativeScrollEvent>,
@@ -158,17 +158,13 @@ const CasesList: React.FC<ICasesList> = ({ casesList = [], isVisitPlan }) => {
scrollAnimation.setValue(offsetY);
};
const renderListItem = (row: ListRenderItemInfo<ICaseItem>) => (
<CaseItem
data={row}
handleSearchChange={handleSearchChange}
testID={`case-${
row.item.type === CaseTypes.TODO ? 'todo' : ''
}-${row.index}`}
/>
)
const renderListItem = (row: ListRenderItemInfo<ICaseItem>) =>
{
const listCase = caseDetails[row.item.caseReferenceId]
return (<CaseItem data={row} handleSearchChange={handleSearchChange} entireCaseData={listCase} testID={`case-${row.item.type === CaseTypes.TODO ? 'todo' : ''}-${row.index}`}/>)
}
const memoizedListItem = useMemo(() => renderListItem, [filteredCasesList]);
const memoizedListItem = useMemo(() => renderListItem, [JSON.stringify(filteredCasesList)]);
const toggleFilterModal = () => setShowFilterModal(!showFilterModal);

View File

@@ -29,27 +29,30 @@ import { formatAmount } from '../../../RN-UI-LIB/src/utlis/amount';
import OnboardingIcon from '../../../RN-UI-LIB/src/Icons/OnboardingIcon';
import CollectionsIcon from '../../../RN-UI-LIB/src/Icons/CollectionsIcon';
import RoundCheckIcon from '../../../RN-UI-LIB/src/Icons/RoundCheckIcon';
import store from "../../store/store";
import { CaseDetail } from "../caseDetails/interface";
interface IListItem {
caseData: ICaseItem;
entireCaseObject?: CaseDetail;
// True if it's from the inside todo screen
isTodoItem?: boolean;
isCompleted?: boolean;
shouldBatchAvatar?:boolean;
}
const ListItem: React.FC<IListItem> = props => {
const { caseData, isCompleted, isTodoItem } = props;
const { caseData, isCompleted, isTodoItem, entireCaseObject, shouldBatchAvatar } = props;
const { caseReferenceId: caseId } = caseData;
const dispatch = useAppDispatch();
if (!isCompleted && caseData.caseStatus === CaseStatuses.CLOSED) {
return null;
}
const intermediateTodoListMap = useAppSelector(state => state.allCases.intermediateTodoListMap)
const selectedTodoListMap = useAppSelector(state => state.allCases.selectedTodoListMap)
const { intermediateTodoListMap, selectedTodoListMap, caseDetails, pinnedList } =
useAppSelector(state => state.allCases);
const detail = caseDetails[caseId]!!;
const detail: CaseDetail = entireCaseObject || store.getState()?.allCases.caseDetails[caseId] || {};
const isNewlyAdded = detail.isNewlyAdded;
const { pinRank } = caseData;
@@ -128,7 +131,7 @@ const ListItem: React.FC<IListItem> = props => {
: COLORS.BACKGROUND.PRIMARY,
},
]}>
<CaseItemAvatar caseData={caseData} />
<CaseItemAvatar caseData={caseData} shouldBatchAvatar={shouldBatchAvatar} />
{!isTodoItem && !isCompleted ? (
<Pressable
onPress={handleAvatarClick}

View File

@@ -49,6 +49,7 @@ const CustomerProfile: React.FC<ICustomerProfile> = props => {
caseDetail,
[DOCUMENT_TYPE.OPTIMIZED_SELFIE, DOCUMENT_TYPE.SELFIE],
false,
false
);
const [vkycUri, setVkycUri] = useState<string>();
const [showVkyc, setShowVkyc] = useState<boolean>(false);

View File

@@ -1,15 +1,10 @@
import { StyleSheet, View } from 'react-native';
import React, { useEffect, useState } from 'react';
import React from 'react';
import { GenericStyles, SCREEN_WIDTH } from '../../../RN-UI-LIB/src/styles';
import VideoPlayer from 'react-native-video-player';
import NavigationHeader from '../../../RN-UI-LIB/src/components/NavigationHeader';
import { goBack } from '../../components/utlis/navigationUtlis';
import { CaseDetail, DOCUMENT_TYPE, IDocument } from './interface';
import {
findDocumentByDocumentType,
getDocumentList,
} from '../../components/utlis/commonFunctions';
import { ISignedRequest, getSignedApi } from '../../action/dataActions';
import { CaseDetail } from './interface';
interface ICustomerProfile {
route: {