NTP-17666 | CallHistory Pagination (#1113)
This commit is contained in:
@@ -47,8 +47,8 @@ export const makeACallToCustomer =
|
||||
if (details?.isCallHistory) {
|
||||
dispatch(
|
||||
fetchCallHistory({
|
||||
loanAccountNumber: payload?.loanAccountNumber,
|
||||
caseId: details?.caseId,
|
||||
deleteExistingHistory: true,
|
||||
})
|
||||
);
|
||||
} else {
|
||||
|
||||
@@ -3,10 +3,12 @@ import store, { AppDispatch } from '../store/store';
|
||||
import { logError } from '../components/utlis/errorUtils';
|
||||
import {
|
||||
ITelephoneNumbers,
|
||||
deleteCallHistory,
|
||||
setCallHistory,
|
||||
setTelephoneDetails,
|
||||
} from '@reducers/telephoneNumbersSlice';
|
||||
import { isFunction } from '@components/utlis/commonFunctions';
|
||||
import { GenericType } from '@common/GenericTypes';
|
||||
|
||||
type FetchTelephoneNumbersParams = {
|
||||
caseId: string;
|
||||
@@ -17,8 +19,9 @@ type FetchTelephoneNumbersParams = {
|
||||
|
||||
type FetchCallHistoryParams = {
|
||||
caseId: string;
|
||||
loanAccountNumber: string;
|
||||
setLoading?: (value: boolean) => void;
|
||||
cursor?: string;
|
||||
deleteExistingHistory?: boolean;
|
||||
};
|
||||
|
||||
export const fetchTelephoneNumber =
|
||||
@@ -45,26 +48,48 @@ export const fetchTelephoneNumber =
|
||||
};
|
||||
|
||||
export const fetchCallHistory =
|
||||
({ caseId, loanAccountNumber, setLoading }: FetchCallHistoryParams) =>
|
||||
({ caseId, cursor = '', setLoading, deleteExistingHistory = false }: FetchCallHistoryParams) =>
|
||||
(dispatch: AppDispatch) => {
|
||||
const caseDetail = store?.getState()?.allCases?.caseDetails?.[caseId] || {};
|
||||
const encoded = encodeURIComponent(cursor);
|
||||
const payload: GenericType = cursor
|
||||
? {
|
||||
cursor: encoded,
|
||||
}
|
||||
: {};
|
||||
const url = getApiUrl(
|
||||
ApiKeys.GET_CALL_HISTORY,
|
||||
{},
|
||||
{
|
||||
caseReferenceId: caseDetail?.caseReferenceId,
|
||||
caseBusinessVertical: caseDetail?.businessVertical,
|
||||
...payload,
|
||||
}
|
||||
);
|
||||
if (deleteExistingHistory) {
|
||||
dispatch(deleteCallHistory({ caseId }));
|
||||
}
|
||||
const isSetLoadingFunction = isFunction(setLoading);
|
||||
if (isSetLoadingFunction) setLoading(true);
|
||||
axiosInstance
|
||||
.get(url)
|
||||
.then((res) => {
|
||||
const hasMoreData = res?.data?.hasNext;
|
||||
const currentCallHistory =
|
||||
store?.getState()?.telephoneNumbers?.callHistory?.[caseId]?.calls || [];
|
||||
const calls = res?.data?.calls || [];
|
||||
// If there is no data and there is more data to fetch, then fetch more data
|
||||
if (!calls?.length && hasMoreData) {
|
||||
dispatch(fetchCallHistory({ caseId, cursor: res?.data?.cursor, setLoading }));
|
||||
return;
|
||||
}
|
||||
dispatch(
|
||||
setCallHistory({
|
||||
caseId: caseId,
|
||||
callHistory: res?.data?.calls,
|
||||
callHistory: {
|
||||
...res?.data,
|
||||
calls: [...currentCallHistory, ...calls] || [],
|
||||
},
|
||||
})
|
||||
);
|
||||
})
|
||||
|
||||
@@ -202,7 +202,7 @@ API_URLS[ApiKeys.GET_PIN_CODES_DETAILS] = '/api/v1/pincodes/{pinCode}';
|
||||
API_URLS[ApiKeys.SYNC_COSMOS_TO_LONGHORN] = '/sync/tele-cosmos-sync';
|
||||
API_URLS[ApiKeys.CALL_CUSTOMER] = '/call-recording/v2/call-request';
|
||||
API_URLS[ApiKeys.SYNC_ACTIVE_CALL_DETAILS] = '/call-recording/call-status';
|
||||
API_URLS[ApiKeys.GET_CALL_HISTORY] = '/call-recording/v2/call-history';
|
||||
API_URLS[ApiKeys.GET_CALL_HISTORY] = '/call-recording/v3/call-history';
|
||||
API_URLS[ApiKeys.SYNC_CALL_FEEDBACK_NUDGE_DETAILS] =
|
||||
|
||||
'/call-recording/acknowledge-feedback-nudge/{callId}';
|
||||
|
||||
@@ -39,7 +39,12 @@ interface ITelephoneNumbersSlice {
|
||||
[key: string]: ITelephoneNumbers[];
|
||||
};
|
||||
callHistory: {
|
||||
[key: string]: ICallHistory[];
|
||||
[key: string]: {
|
||||
calls?: ICallHistory[];
|
||||
hasNext?: boolean;
|
||||
isLast?: boolean;
|
||||
cursor?: string;
|
||||
};
|
||||
};
|
||||
callActivity: {
|
||||
[key: string]: ICallActivity;
|
||||
@@ -71,6 +76,9 @@ export const telephoneNumbersSlice = createSlice({
|
||||
setCallHistory: (state, action) => {
|
||||
state.callHistory[action?.payload?.caseId] = action?.payload?.callHistory;
|
||||
},
|
||||
deleteCallHistory: (state, action) => {
|
||||
state.callHistory[action?.payload?.caseId] = {};
|
||||
},
|
||||
setTelephoneDetails: (state, action) => {
|
||||
state.telephoneNumbers[action?.payload?.caseId] = action?.payload?.data?.telephones;
|
||||
state.callActivity[action?.payload?.caseId] = {
|
||||
@@ -84,7 +92,12 @@ export const telephoneNumbersSlice = createSlice({
|
||||
},
|
||||
});
|
||||
|
||||
export const { setTelephoneNumbers, setCallHistory, setTelephoneDetails, setCallAttemptedOn } =
|
||||
telephoneNumbersSlice.actions;
|
||||
export const {
|
||||
setTelephoneNumbers,
|
||||
setCallHistory,
|
||||
deleteCallHistory,
|
||||
setTelephoneDetails,
|
||||
setCallAttemptedOn,
|
||||
} = telephoneNumbersSlice.actions;
|
||||
|
||||
export default telephoneNumbersSlice.reducer;
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { ActivityIndicator, RefreshControl, ScrollView, StyleSheet, View } from 'react-native';
|
||||
import {
|
||||
ActivityIndicator,
|
||||
FlatList,
|
||||
RefreshControl,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import Text from '@rn-ui-lib/components/Text';
|
||||
import { GenericStyles } from '@rn-ui-lib/styles';
|
||||
import { COLORS } from '@rn-ui-lib/colors';
|
||||
@@ -13,29 +20,56 @@ import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
|
||||
|
||||
const CallHistory = (props: ICallHistory) => {
|
||||
const { caseId } = props;
|
||||
const loanAccountNumber = useAppSelector(
|
||||
(state) => state?.allCases?.caseDetails?.[caseId]?.loanAccountNumber
|
||||
);
|
||||
|
||||
const callHistoryDetails = useAppSelector(
|
||||
(state) => state?.telephoneNumbers?.callHistory?.[caseId]
|
||||
);
|
||||
|
||||
const callHistoryDetails =
|
||||
useAppSelector((state) => state?.telephoneNumbers?.callHistory?.[caseId]) || {};
|
||||
const calls = callHistoryDetails?.calls || [];
|
||||
const [isRefreshing, setIsRefreshing] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_CALL_HISTORY_LOADED);
|
||||
dispatch(fetchCallHistory({ loanAccountNumber, caseId, setLoading }));
|
||||
dispatch(fetchCallHistory({ caseId, setLoading, deleteExistingHistory: true }));
|
||||
}, []);
|
||||
|
||||
const refreshHandler = () => {
|
||||
dispatch(fetchCallHistory({ loanAccountNumber, caseId, setLoading: setIsRefreshing }));
|
||||
dispatch(
|
||||
fetchCallHistory({ caseId, setLoading: setIsRefreshing, deleteExistingHistory: true })
|
||||
);
|
||||
};
|
||||
|
||||
if (loading)
|
||||
const fetchMoreData = () => {
|
||||
const hasMoreData = callHistoryDetails?.hasNext;
|
||||
if (hasMoreData) {
|
||||
dispatch(fetchCallHistory({ caseId, cursor: callHistoryDetails?.cursor, setLoading }));
|
||||
}
|
||||
};
|
||||
|
||||
const listFooterComponent = () => {
|
||||
if (calls?.length) {
|
||||
const hasMoreData = callHistoryDetails?.hasNext;
|
||||
if (hasMoreData) {
|
||||
return (
|
||||
<View
|
||||
style={[GenericStyles.centerAlignedRow, GenericStyles.mb12, styles.loadingContainer]}
|
||||
>
|
||||
{loading ? <ActivityIndicator color={COLORS.BASE.BLUE} /> : null}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (!hasMoreData) {
|
||||
return (
|
||||
<View style={[GenericStyles.centerAlignedRow, GenericStyles.mt20, GenericStyles.mb12]}>
|
||||
<Text style={{ color: COLORS.TEXT.LIGHT }}>You have reached the end of the list</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
if ((loading && !calls?.length) || isRefreshing)
|
||||
return (
|
||||
<View
|
||||
style={[GenericStyles.fill, GenericStyles.centerAlignedRow, GenericStyles.whiteBackground]}
|
||||
@@ -44,7 +78,7 @@ const CallHistory = (props: ICallHistory) => {
|
||||
</View>
|
||||
);
|
||||
|
||||
if (!callHistoryDetails?.length)
|
||||
if (!calls?.length)
|
||||
return (
|
||||
<ScrollView
|
||||
contentContainerStyle={[
|
||||
@@ -61,24 +95,31 @@ const CallHistory = (props: ICallHistory) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<ScrollView
|
||||
style={[GenericStyles.ph16, GenericStyles.pv16, GenericStyles.whiteBackground]}
|
||||
refreshControl={<RefreshControl refreshing={isRefreshing} onRefresh={refreshHandler} />}
|
||||
>
|
||||
<View style={GenericStyles.pb24}>
|
||||
{callHistoryDetails.map((callHistory, index) => (
|
||||
<View style={[GenericStyles.fill, GenericStyles.whiteBackground]}>
|
||||
<FlatList
|
||||
data={calls}
|
||||
refreshControl={<RefreshControl refreshing={isRefreshing} onRefresh={refreshHandler} />}
|
||||
renderItem={({ item, index }) => (
|
||||
<CallHistoryItem
|
||||
key={callHistory.createdAtEpoch}
|
||||
callHistory={callHistory}
|
||||
isLastElement={index === callHistoryDetails.length - 1}
|
||||
key={item?.createdAtEpoch}
|
||||
callHistory={item}
|
||||
isLastElement={index === calls?.length - 1}
|
||||
caseId={caseId}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
</ScrollView>
|
||||
)}
|
||||
contentContainerStyle={[GenericStyles.ph16, GenericStyles.pv16]}
|
||||
onEndReached={fetchMoreData}
|
||||
onEndReachedThreshold={0.1}
|
||||
ListFooterComponent={listFooterComponent()}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({});
|
||||
const styles = StyleSheet.create({
|
||||
loadingContainer: {
|
||||
height: 10,
|
||||
},
|
||||
});
|
||||
|
||||
export default CallHistory;
|
||||
|
||||
@@ -39,8 +39,8 @@ const CallInfo = () => {
|
||||
dispatch(fetchTelephoneNumber({ caseId, caseBusinessVertical, loanAccountNumber }));
|
||||
dispatch(
|
||||
fetchCallHistory({
|
||||
loanAccountNumber,
|
||||
caseId,
|
||||
deleteExistingHistory: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user