NTP-6736 | integration done

This commit is contained in:
Ashish Deo
2024-10-24 19:00:39 +05:30
parent 3a885de302
commit 06950c6549
10 changed files with 328 additions and 323 deletions

View File

@@ -105,6 +105,7 @@ export enum ApiKeys {
DOWNLOAD_LATEST_APP = 'DOWNLOAD_LATEST_APP',
GET_SIGNED_URL_V2 = 'GET_SIGNED_URL_V2',
GET_SIGNED_URL_FOR_REPORTEE_V2 = 'GET_SIGNED_URL_FOR_REPORTEE_V2',
ALL_ESCALATIONS = 'ALL_ESCALATIONS',
}
export const API_URLS: Record<ApiKeys, string> = {} as Record<ApiKeys, string>;
@@ -200,6 +201,7 @@ API_URLS[ApiKeys.FETCH_AGENT_DOCUMENTS] = '/documents/agent';
API_URLS[ApiKeys.FETCH_DOCUMENT_SPECIFIC_LANGUAGE] = '/documents/language/{loanAccountNumber}';
API_URLS[ApiKeys.SEND_COMMUNICATION_NAVI_ACCOUNT] = '/navi-communications/{loanAccountNumber}';
API_URLS[ApiKeys.GENERATE_DYNAMIC_DOCUMENT] = '/documents/generate/{loanAccountNumber}';
API_URLS[ApiKeys.ALL_ESCALATIONS] = '/customer-escalation';
API_URLS[ApiKeys.DOWNLOAD_LATEST_APP] = 'https://longhorn.navi.com/api/app/download';
export const API_STATUS_CODE = {

View File

@@ -0,0 +1,47 @@
import { createSlice } from '@reduxjs/toolkit';
interface IEscalationsSlice {
escalationData : IAllEscalationData[];
isLoading : boolean;
pageData :pageData;
}
interface pageData {
totalPages : number;
totalElements : number;
}
interface IAllEscalationData {
createdAt : string;
loanAccountNumber :string;
status : string;
title : string;
voc : string;
}
const initialState = {
escalationData : [],
isLoading : false,
pageData: {} as pageData
} as IEscalationsSlice;
const escalationsSlice = createSlice({
name: 'escalations',
initialState,
reducers: {
setEscalationData: (state, action) => {
state.escalationData = action.payload;
},
setIsLoading: (state, action) => {
state.isLoading = action.payload;
},
setPageData: (state, action) => {
state.pageData = action.payload;
}
},
});
export const { setEscalationData, setIsLoading, setPageData } = escalationsSlice.actions;
export default escalationsSlice.reducer;

View File

@@ -84,6 +84,7 @@ const ListItem: React.FC<IListItem> = (props) => {
interactionStatus,
totalOverdueAmount,
distanceInKm,
escalationData,
} = caseListItemDetailObj;
const isVisitPlanStatusLocked = useAppSelector(
@@ -206,20 +207,17 @@ const ListItem: React.FC<IListItem> = (props) => {
: TAG_CONTAINER_WIDTH.DEFAULT,
};
const isEscalationCase = true;
const isActiveEscalationCase = true;
const isPastEscalationCase = false;
const escalationCount = 4;
const activeEscalationCaseCount = 2;
const pastEscalationCaseCount = 3;
const totalEscalationCaseCount = activeEscalationCaseCount + pastEscalationCaseCount;
const isEscalationCase = escalationData !== undefined;
const isActiveEscalationCase = Number(escalationData?.activeEscalationCount) > 0;
const activeEscalationCount = Number(escalationData?.activeEscalationCount);
const pastEscalationCount = Number(escalationData?.pastEscalationCount);
return (
<Pressable onPress={handleCaseClick}>
<View>
</View>
<View
style={[
GenericStyles.row,
styles.listItem,
getShadowStyle(2),
{
@@ -229,107 +227,120 @@ const ListItem: React.FC<IListItem> = (props) => {
? COLORS.BACKGROUND.SILVER
: COLORS.BACKGROUND.PRIMARY,
},
]}
>
{isEscalationCase ? (
<View style={[styles.escalationContainer, GenericStyles.row, GenericStyles.alignCenter, GenericStyles.w100, {
backgroundColor: isActiveEscalationCase ? COLORS.BACKGROUND.RED : COLORS.BACKGROUND.YELLOW_LIGHT
}]}>
<FlagIcon fillColor={isActiveEscalationCase ? '#FF0000' : '#FFB800'} />
<Text small style={[isActiveEscalationCase ? styles.activeEscalationText : styles.pastEscalationText]}>
{`${totalEscalationCaseCount} `}{isActiveEscalationCase ? 'Active Escalations' : 'Past Escalations'}
</Text>
</View>
) : null}
<CaseItemAvatar
caseDetailObj={getCaseItemAvatarCaseDetailObj}
shouldBatchAvatar={shouldBatchAvatar}
/>
{showVisitPlanBtn ? (
<Pressable onPress={handleAvatarClick} style={styles.selectBtn}>
<RoundCheckIcon focused={isCaseSelected} />
</Pressable>
) : null}
{showInVisitPlanTag && (
<View style={[GenericStyles.absolute, styles.visitPlanContainer]}>
<Text style={[GenericStyles.fontSize12, styles.visitPlanText]}>In visit plan</Text>
</View>
)}
{nearbyCaseView && distanceInKm && (
<View style={[GenericStyles.absolute, styles.distanceContainer]}>
<Text style={[GenericStyles.fontSize12, styles.distanceText]}>
{relativeDistanceFormatter(distanceInKm)} km away
</Text>
</View>
)}
<View style={[styles.caseItemInfo]}>
<View style={[styles.tagContainer, widthStyle]}>
{paymentStatus ? (
<View style={[GenericStyles.mr8, GenericStyles.mb8]}>
<Tag
variant={paymentStatusMapping[paymentStatus]?.variant || TagVariant.alert}
text={(paymentStatusMapping[paymentStatus]?.label || paymentStatus) as string}
/>
</View>
) : null}
{collectionTag ? (
<View style={[GenericStyles.mr8]}>
<Tag variant={TagVariant.gray} text={collectionTag} />
</View>
) : null}
{!isVisitPlan && distanceOfCaseItem ? (
<View style={GenericStyles.mb4}>
<Tag
tagIcon={
<LocationDistanceIcon
iconColor={isNearestCaseView ? COLORS.TEXT.BLUE_DARK_2 : COLORS.TEXT.GREY_3}
backgroundColor={
isNearestCaseView ? COLORS.BACKGROUND.BLUE : COLORS.BACKGROUND.BLUE_LIGHT_3
}
/>
}
text={Number(distanceOfCaseItem?.toFixed(1)) + ' KM'}
variant={isNearestCaseView ? TagVariant.darkBlue : TagVariant.darkGray}
/>
</View>
) : null}
</View>
<Heading numberOfLines={1} type={'h5'} bold dark>
{customerName}
</Heading>
{taskTitle ? (
<Text dark bold ellipsizeMode="tail" style={styles.address}>
<Text light>
{/* @ts-ignore */}
<Text>{TaskTitleUIMapping[taskTitle]}</Text>
{displayAddress ? `: ${displayAddress}` : null}
isActiveEscalationCase ? (
<View style={[styles.escalationContainer, GenericStyles.row, GenericStyles.alignCenter, GenericStyles.w100, {
backgroundColor: COLORS.BACKGROUND.RED
}]}>
<FlagIcon fillColor='#FF0000' />
<Text small style={styles.activeEscalationText}>
{`${activeEscalationCount} Active Escalation${activeEscalationCount === 1 ? '' : 's'}`}
</Text>
</Text>
</View>
) : (
<Text dark bold ellipsizeMode="tail" style={styles.address}>
<Text light>{displayAddress}</Text>
</Text>
<View style={[styles.escalationContainer, GenericStyles.row, GenericStyles.alignCenter, GenericStyles.w100, {
backgroundColor: COLORS.BACKGROUND.YELLOW_LIGHT
}]}>
<FlagIcon fillColor='#FFB800' />
<Text small style={styles.pastEscalationText}>
{`${pastEscalationCount} Past Escalation${pastEscalationCount === 1 ? '' : 's'}`}
</Text>
</View>
)
) : null}
<View style={[GenericStyles.row, GenericStyles.p12]}>
<CaseItemAvatar
caseDetailObj={getCaseItemAvatarCaseDetailObj}
shouldBatchAvatar={shouldBatchAvatar}
/>
{showVisitPlanBtn ? (
<Pressable onPress={handleAvatarClick} style={styles.selectBtn}>
<RoundCheckIcon focused={isCaseSelected} />
</Pressable>
) : null}
{showInVisitPlanTag && (
<View style={[GenericStyles.absolute, styles.visitPlanContainer]}>
<Text style={[GenericStyles.fontSize12, styles.visitPlanText]}>In visit plan</Text>
</View>
)}
<View>
{is1To30FieldAgent ? (
<Text small style={[styles.caseStatusText, styles.borderTop]} bold>
Total due {formatAmount(totalOverdueAmount, false)}
{' '}DPD Cycle {dpdCycle}
{nearbyCaseView && distanceInKm && (
<View style={[GenericStyles.absolute, styles.distanceContainer]}>
<Text style={[GenericStyles.fontSize12, styles.distanceText]}>
{relativeDistanceFormatter(distanceInKm)} km away
</Text>
</View>
)}
<View style={[styles.caseItemInfo]}>
<View style={[styles.tagContainer, widthStyle]}>
{paymentStatus ? (
<View style={[GenericStyles.mr8, GenericStyles.mb8]}>
<Tag
variant={paymentStatusMapping[paymentStatus]?.variant || TagVariant.alert}
text={(paymentStatusMapping[paymentStatus]?.label || paymentStatus) as string}
/>
</View>
) : null}
{collectionTag ? (
<View style={[GenericStyles.mr8]}>
<Tag variant={TagVariant.gray} text={collectionTag} />
</View>
) : null}
{!isVisitPlan && distanceOfCaseItem ? (
<View style={GenericStyles.mb4}>
<Tag
tagIcon={
<LocationDistanceIcon
iconColor={isNearestCaseView ? COLORS.TEXT.BLUE_DARK_2 : COLORS.TEXT.GREY_3}
backgroundColor={
isNearestCaseView ? COLORS.BACKGROUND.BLUE : COLORS.BACKGROUND.BLUE_LIGHT_3
}
/>
}
text={Number(distanceOfCaseItem?.toFixed(1)) + ' KM'}
variant={isNearestCaseView ? TagVariant.darkBlue : TagVariant.darkGray}
/>
</View>
) : null}
</View>
<Heading numberOfLines={1} type={'h5'} bold dark>
{customerName}
</Heading>
{taskTitle ? (
<Text dark bold ellipsizeMode="tail" style={styles.address}>
<Text light>
{/* @ts-ignore */}
<Text>{TaskTitleUIMapping[taskTitle]}</Text>
{displayAddress ? `: ${displayAddress}` : null}
</Text>
</Text>
) : (
<Text small style={[styles.caseStatusText, styles.borderTop]} bold>
Total due {formatAmount(totalOverdueAmount, false)}
{' '}DPD bucket {dpdBucket}
<Text dark bold ellipsizeMode="tail" style={styles.address}>
<Text light>{displayAddress}</Text>
</Text>
)}
{caseInteractionStatus ? (
<Text small style={styles.caseStatusText} bold>
{caseInteractionStatus}
</Text>
) : null}
<View>
{is1To30FieldAgent ? (
<Text small style={[styles.caseStatusText, styles.borderTop]} bold>
Total due {formatAmount(totalOverdueAmount, false)}
{' '}DPD Cycle {dpdCycle}
</Text>
) : (
<Text small style={[styles.caseStatusText, styles.borderTop]} bold>
Total due {formatAmount(totalOverdueAmount, false)}
{' '}DPD bucket {dpdBucket}
</Text>
)}
{caseInteractionStatus ? (
<Text small style={styles.caseStatusText} bold>
{caseInteractionStatus}
</Text>
) : null}
</View>
</View>
</View>
</View>
@@ -339,17 +350,15 @@ const ListItem: React.FC<IListItem> = (props) => {
const styles = StyleSheet.create({
listItem: {
padding: 12,
borderRadius: 8,
marginVertical: 6,
marginBottom: 12,
position: 'relative',
overflow: 'hidden'
},
escalationContainer: {
position: 'absolute',
height: 26,
paddingLeft: 8,
paddingRight: 8,
borderBottomRightRadius: 6,
borderTopLeftRadius: 8,
},
activeEscalationText: {

View File

@@ -344,3 +344,14 @@ export enum FiltePlaceholderText {
CASES = 'cases',
MY_CASES = 'my cases',
}
export interface IRecentEscalationDetails {
customerVoice: string;
createdAt: string;
}
export interface IEscalationSummary {
pastEscalationCount: number;
activeEscalationCount: number;
recentEscalationDetails: IRecentEscalationDetails;
}

View File

@@ -40,6 +40,7 @@ const CollectionCaseDetails: React.FC<ICaseDetails> = (props) => {
},
} = props;
const caseDetail = useAppSelector((state: RootState) => state.allCases.caseDetails[caseId]) || {};
const isActiveEscalation = caseDetail.escalationData !== undefined;
const isCallActive = useAppSelector(
(state: RootState) => state?.activeCall?.activeCallDetails?.callActive
);
@@ -127,7 +128,7 @@ const CollectionCaseDetails: React.FC<ICaseDetails> = (props) => {
>
<ViewAddressSection caseId={caseId} />
<EmiDetailsSection caseId={caseId} />
<EscalationsSection caseId={caseId} />
{isActiveEscalation ? (<EscalationsSection caseId={caseId} />): null}
<CollectMoneySection caseId={caseId} />
<FeedbackDetailsSection caseId={caseId} />
</Animated.View>

View File

@@ -315,6 +315,18 @@ export interface CaseDetail {
employmentDetail?: EmploymentDetails;
unpaidDays?: number;
addressStringType?: string;
escalationData ?: escalationData;
}
export interface recentEscalationDetails {
createdAt : string;
customerVoice : string;
}
export interface escalationData {
activeEscalationCount : number;
pastEscalationCount : number;
recentEscalationDetails : recentEscalationDetails;
}
export interface AddressesGeolocationPayload {

View File

@@ -6,188 +6,49 @@ import useIsOnline from '../../hooks/useIsOnline';
import { addClickstreamEvent } from '../../services/clickstreamEventService';
import { goBack } from '../../components/utlis/navigationUtlis';
import { toast } from '../../../RN-UI-LIB/src/components/toast';
import { GenericStyles, SCREEN_HEIGHT, getShadowStyle } from '../../../RN-UI-LIB/src/styles';
import { GenericStyles, getShadowStyle } from '../../../RN-UI-LIB/src/styles';
import NavigationHeader from '../../../RN-UI-LIB/src/components/NavigationHeader';
import SuspenseLoader from '../../../RN-UI-LIB/src/components/suspense_loader/SuspenseLoader';
import LineLoader from '../../../RN-UI-LIB/src/components/suspense_loader/LineLoader';
import Text from '../../../RN-UI-LIB/src/components/Text';
import { COLORS } from '../../../RN-UI-LIB/src/styles/colors';
import Pagination from '../../../RN-UI-LIB/src/components/pagination/Pagination';
import { GenericObject } from '@common/GenericTypes';
import FlagIcon from '@assets/icons/FlagIcon';
import Tag, { TagVariant } from '@rn-ui-lib/components/Tag';
import { useAppDispatch, useAppSelector } from '@hooks';
import { RootState } from '@store';
import { getAllEscalations } from './actions';
import dayjs from 'dayjs';
interface IEscalationsDetails {
route: {
params: {
caseId: string;
loanAccountNumber: string;
};
};
}
const Escalations = () => {
const Escalations: React.FC<IEscalationsDetails> = (props) => {
const [escalationsList, setEscalationsList] = useState<GenericObject[]>([]);
const [totalPage, setTotalPage] = useState(0);
const [loading, setLoading] = useState(false);
const {
route: {
params: { caseId, loanAccountNumber },
},
} = props;
const {escalationData, isLoading, pageData} = useAppSelector((state: RootState) => state.escalationSlice);
const [currentPage, setCurrentPage] = useState(1);
const isOnline = useIsOnline();
const getAllEscalations = useCallback(() => {
setTotalPage(escalationsList.length)
}, [currentPage]);
const dispatch = useAppDispatch();
useEffect(() => {
setLoading(true);
setEscalationsList([{
id: 1,
title: 'Physical assault/threatening to physically assault',
raisedOn: '9 May, 2024',
time: '2:29 PM',
status: 'Closed',
description: 'Extension of time for paying dues.',
isActiveEscalation: false, // Closed = not active
},
{
id: 2,
title: 'Miscommunication about loan terms',
raisedOn: '15 April, 2024',
time: '10:15 AM',
status: 'In Progress',
description: 'Clarification required regarding interest rates.',
isActiveEscalation: true, // In Progress = active
},
{
id: 3,
title: 'Unauthorized access to account',
raisedOn: '28 March, 2024',
time: '4:45 PM',
status: 'Open',
description: 'Suspicious activity detected in the bank account.',
isActiveEscalation: true, // Open = active
},
{
id: 4,
title: 'Delayed processing of payment',
raisedOn: '5 March, 2024',
time: '1:00 PM',
status: 'Closed',
description: 'Payment was not processed on time.',
isActiveEscalation: false, // Closed = not active
},
{
id: 5,
title: 'Incorrect charges applied',
raisedOn: '20 February, 2024',
time: '9:30 AM',
status: 'Resolved',
description: 'Extra charges applied without notice.',
isActiveEscalation: false, // Resolved = not active
},
{
id: 3,
title: 'Unauthorized access to account',
raisedOn: '28 March, 2024',
time: '4:45 PM',
status: 'Open',
description: 'Suspicious activity detected in the bank account.',
isActiveEscalation: true, // Open = active
},
{
id: 4,
title: 'Delayed processing of payment',
raisedOn: '5 March, 2024',
time: '1:00 PM',
status: 'Closed',
description: 'Payment was not processed on time.',
isActiveEscalation: false, // Closed = not active
},
{
id: 5,
title: 'Incorrect charges applied',
raisedOn: '20 February, 2024',
time: '9:30 AM',
status: 'Resolved',
description: 'Extra charges applied without notice.',
isActiveEscalation: false, // Resolved = not active
},
{
id: 3,
title: 'Unauthorized access to account',
raisedOn: '28 March, 2024',
time: '4:45 PM',
status: 'Open',
description: 'Suspicious activity detected in the bank account.',
isActiveEscalation: true, // Open = active
},
{
id: 4,
title: 'Delayed processing of payment',
raisedOn: '5 March, 2024',
time: '1:00 PM',
status: 'Closed',
description: 'Payment was not processed on time.',
isActiveEscalation: false, // Closed = not active
},
{
id: 5,
title: 'Incorrect charges applied',
raisedOn: '20 February, 2024',
time: '9:30 AM',
status: 'Resolved',
description: 'Extra charges applied without notice.',
isActiveEscalation: false, // Resolved = not active
}, {
id: 3,
title: 'Unauthorized access to account',
raisedOn: '28 March, 2024',
time: '4:45 PM',
status: 'Open',
description: 'Suspicious activity detected in the bank account.',
isActiveEscalation: true, // Open = active
},
{
id: 4,
title: 'Delayed processing of payment',
raisedOn: '5 March, 2024',
time: '1:00 PM',
status: 'Closed',
description: 'Payment was not processed on time.',
isActiveEscalation: false, // Closed = not active
},
{
id: 5,
title: 'Incorrect charges applied',
raisedOn: '20 February, 2024',
time: '9:30 AM',
status: 'Resolved',
description: 'Extra charges applied without notice.',
isActiveEscalation: false, // Resolved = not active
},
{
id: 3,
title: 'Unauthorized access to account',
raisedOn: '28 March, 2024',
time: '4:45 PM',
status: 'Open',
description: 'Suspicious activity detected in the bank account.',
isActiveEscalation: true, // Open = active
},
{
id: 4,
title: 'Delayed processing of payment',
raisedOn: '5 March, 2024',
time: '1:00 PM',
status: 'Closed',
description: 'Payment was not processed on time.',
isActiveEscalation: false, // Closed = not active
},
{
id: 5,
title: 'Incorrect charges applied',
raisedOn: '20 February, 2024',
time: '9:30 AM',
status: 'Resolved',
description: 'Extra charges applied without notice.',
isActiveEscalation: false, // Resolved = not active
}
]);
getAllEscalations();
dispatch(getAllEscalations(loanAccountNumber, { page_no: currentPage-1, page_size: 10 }));
}, [currentPage]);
useEffect(() => {
if (!isOnline) {
setCurrentPage(1);
@@ -206,22 +67,18 @@ const Escalations = () => {
setCurrentPage(page);
};
const isActiveEscalationCase = true;
return (
<View style={[GenericStyles.fill, GenericStyles.whiteBackground]}>
<NavigationHeader title={'All Escalations'} onBack={goBack} />
<ScrollView style={[GenericStyles.ph16, GenericStyles.mt16, GenericStyles.fill]}>
<SuspenseLoader
loading={false}
loading={isLoading}
fallBack={
<>
{[...Array(8).keys()].map(() => (
<LineLoader
width={'100%'}
height={75}
height={150}
style={[GenericStyles.br6, { marginBottom: 20 }]}
/>
))}
@@ -229,25 +86,25 @@ const Escalations = () => {
}
>
<View>
{escalationsList?.length ? (
{escalationData?.length ? (
<>
{escalationsList.map((escalation) => (
<View key={escalation.id}>
{escalationData.map((escalation) => (
<View key={escalation.voc} >
<View
style={[
GenericStyles.whiteBackground,
GenericStyles.w100,
getShadowStyle(2),
GenericStyles.mt16,
styles.br16,
styles.secondSection
]}
>
<View style={[GenericStyles.row, GenericStyles.pt16, GenericStyles.pl16]} >
<View style={[GenericStyles.row, GenericStyles.p16,]} >
<View style={[styles.flagContainer, GenericStyles.mr16, GenericStyles.centerAligned, {
backgroundColor: escalation.isActiveEscalation ? COLORS.BACKGROUND.RED : COLORS.BACKGROUND.YELLOW_LIGHT
backgroundColor: escalation.status === 'OPEN' ? COLORS.BACKGROUND.RED : COLORS.BACKGROUND.YELLOW_LIGHT
}]}>
<FlagIcon fillColor={escalation.isActiveEscalation ? '#FF0000' : '#FFB800'} />
<FlagIcon fillColor={escalation.status === 'OPEN' ? '#FF0000' : '#FFB800'} />
</View>
<View style={[styles.upperContainer]}>
@@ -259,17 +116,17 @@ const Escalations = () => {
<View style={[GenericStyles.row, GenericStyles.spaceBetween]}>
<View style={[GenericStyles.row]}>
<Text style={[GenericStyles.fontSize13, GenericStyles.mr4,styles.textColorGrayscale2]}>
{escalation.raisedOn}
{dayjs(escalation.createdAt).format('DD MMM YYYY')}
</Text>
<Text style={[GenericStyles.fontSize13, styles.textColorGrayscale3]}>
{'|'}
</Text>
<Text style={[GenericStyles.fontSize13, GenericStyles.ml4, styles.textColorGrayscale2]}>
{escalation.time}
{dayjs(escalation.createdAt).format('hh:mm A')}
</Text>
</View>
{escalation.isActiveEscalation ? (
{escalation.status === 'OPEN' ? (
<Tag variant={TagVariant.error} text="Open" />
) : (
<Tag variant={TagVariant.yellow} text="Closed" />
@@ -281,7 +138,7 @@ const Escalations = () => {
<View style={styles.horizontalLine} />
<View style={[GenericStyles.p16]}>
<Text style={[styles.textColorGrayscale3]}>Description</Text>
<Text style={[styles.textColorGrayscale2,GenericStyles.fontSize13]}>{escalation.description}</Text>
<Text style={[styles.textColorGrayscale2,GenericStyles.fontSize13]}>{escalation.voc}</Text>
</View>
</View>
</View>
@@ -300,11 +157,11 @@ const Escalations = () => {
</View>
</SuspenseLoader>
</ScrollView>
{escalationsList?.length && totalPage > 1 ? (
{escalationData?.length && pageData?.totalPages > 1 ? (
<Pagination
onPageChange={handlePageChange}
currentPage={currentPage}
totalPages={totalPage}
totalPages={pageData.totalPages}
/>
) : null}
</View>
@@ -312,11 +169,13 @@ const Escalations = () => {
};
const styles = StyleSheet.create({
br16: {
secondSection: {
alignSelf: 'center',
borderRadius: 16,
width: '98%',
},
horizontalLine: {
backgroundColor: COLORS.BACKGROUND.BLACK,
backgroundColor: COLORS.TEXT.LIGHT,
width: '100%',
height: 1,
marginTop: 16,
@@ -330,8 +189,6 @@ const styles = StyleSheet.create({
textColorGrayscale3: {
color: COLORS.TEXT.LIGHT,
},
upperContainer: {
width: 248,
},

View File

@@ -11,6 +11,7 @@ import { useAppSelector } from '@hooks';
import { addClickstreamEvent } from '@services/clickstreamEventService';
import { CaseDetailStackEnum } from '../caseDetails/CaseDetailStack';
import FlagIcon from '@assets/icons/FlagIcon';
import dayjs from 'dayjs';
interface IEscalationsSection {
caseId: string;
@@ -19,24 +20,27 @@ interface IEscalationsSection {
const EscalationsSection = ({ caseId }: IEscalationsSection) => {
const caseDetail = useAppSelector((state: RootState) => state.allCases?.caseDetails?.[caseId]) || {};
const { loanAccountNumber } = caseDetail;
const { escalationData, loanAccountNumber } = caseDetail;
const handleOnPressClick = () => {
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_VIEW_ALL_ESCALATIONS_SCREEN_CLICKED, {
lan: loanAccountNumber,
});
navigateToScreen(CaseDetailStackEnum.ESCALATIONS);
navigateToScreen(CaseDetailStackEnum.ESCALATIONS, {
loanAccountNumber,
caseId,
})
};
const isActiveEscalationCase = Number(escalationData?.activeEscalationCount) > 0;
const activeEscalationCount = Number(escalationData?.activeEscalationCount);
const pastEscalationCount = Number(escalationData?.pastEscalationCount);
const totalEscalationsCount = activeEscalationCount + pastEscalationCount;
const escalationCreatedAt = escalationData?.recentEscalationDetails.createdAt;
const customerVoice = escalationData?.recentEscalationDetails.customerVoice;
const activeEscalationsCount = 2;
const pastEscalationsCount = 3;
const totalEscalationsCount = activeEscalationsCount + pastEscalationsCount; // might break for 2-3 digit number
const isActiveEscalationCase = true;
return (
<View
style={[
@@ -54,46 +58,55 @@ const EscalationsSection = ({ caseId }: IEscalationsSection) => {
>
<View style={GenericStyles.fill}>
<View style={[styles.escalationContainer, GenericStyles.row, GenericStyles.centerAligned, {
backgroundColor: isActiveEscalationCase ? COLORS.BACKGROUND.RED : COLORS.BACKGROUND.YELLOW_LIGHT
}]}>
<FlagIcon fillColor={isActiveEscalationCase ? '#FF0000' : '#FFB800'} />
<Text small style={[isActiveEscalationCase ? styles.activeEscalationText : styles.pastEscalationText]}>
{`${totalEscalationsCount} `}{isActiveEscalationCase ? 'Active Escalations' : 'Past Escalations'}
</Text>
</View>
{isActiveEscalationCase ? (
<View style={[styles.escalationContainer, GenericStyles.row, GenericStyles.centerAligned, {
backgroundColor: COLORS.BACKGROUND.RED
}]}>
<FlagIcon fillColor='#FF0000' />
<Text small style={styles.activeEscalationText}>
{`${activeEscalationCount} Active Escalation${activeEscalationCount === 1 ? '' : 's'}`}
</Text>
</View>
) : (
<View style={[styles.escalationContainer, GenericStyles.row, GenericStyles.centerAligned, {
backgroundColor: COLORS.BACKGROUND.YELLOW_LIGHT
}]}>
<FlagIcon fillColor='#FFB800' />
<Text small style={styles.pastEscalationText}>
{`${pastEscalationCount} Past Escalation${pastEscalationCount === 1 ? '' : 's'}`}
</Text>
</View>)
}
<View style={[GenericStyles.columnDirection, GenericStyles.fill,,GenericStyles.pl16]}>
<View style={[GenericStyles.columnDirection, GenericStyles.fill, , GenericStyles.pl16]}>
<Text dark bold style={[GenericStyles.fontSize14, GenericStyles.mb4]}>
{'Fake/False commitments/information'}
{customerVoice}
</Text>
<View style={[GenericStyles.row, GenericStyles.alignCenter]}>
<Text style={[GenericStyles.fontSize13]}>
{'Raised on:'}
</Text>
<Text style={[GenericStyles.fontSize13, GenericStyles.ml4,GenericStyles.mr4]}>
{'9 May, 2024'}
<Text style={[GenericStyles.fontSize13, GenericStyles.ml4, GenericStyles.mr4,styles.textColorGrayscale2]}>
{dayjs(escalationCreatedAt).format('DD MMM YYYY')}
</Text>
<Text style={[GenericStyles.fontSize13]}>
<Text style={[GenericStyles.fontSize13, styles.textColorGrayscale3]}>
{'|'}
</Text>
<Text style={[GenericStyles.fontSize13,GenericStyles.ml4]}>
{'2:29 PM'}
<Text style={[GenericStyles.fontSize13, GenericStyles.ml4,styles.textColorGrayscale2]}>
{dayjs(escalationCreatedAt).format('hh:mm A')}
</Text>
</View>
</View>
<View style={[GenericStyles.row, GenericStyles.alignCenter, GenericStyles.pt12,GenericStyles.pb16, GenericStyles.pl16]}>
<View style={[GenericStyles.row, GenericStyles.alignCenter, GenericStyles.pt12, GenericStyles.pb16, GenericStyles.pl16]}>
<Text style={[styles.viewAllButton]}>View all {`(${totalEscalationsCount})`}</Text>
<Chevron fillColor={COLORS.TEXT.BLUE} />
</View>
</View>
</TouchableOpacity>
</TouchableOpacity>
</View>
</View>
);
@@ -106,8 +119,7 @@ export const styles = StyleSheet.create({
paddingRight: 8,
borderBottomRightRadius: 6,
borderTopLeftRadius: 16,
width : 148,
width: 148,
},
activeEscalationText: {
color: COLORS.TEXT.RED,
@@ -117,6 +129,12 @@ export const styles = StyleSheet.create({
color: COLORS.TEXT.YELLOW,
marginLeft: 4,
},
textColorGrayscale2: {
color: COLORS.TEXT.BLACK,
},
textColorGrayscale3: {
color: COLORS.TEXT.LIGHT,
},
viewAllButton: {
color: COLORS.TEXT.BLUE,
fontSize: 12,

View File

@@ -0,0 +1,46 @@
import axiosInstance, { getApiUrl, ApiKeys } from "@components/utlis/apiHelper";
import { logError } from "@components/utlis/errorUtils";
import { setEscalationData, setIsLoading, setPageData } from "@reducers/escalationSlice";
import { AppDispatch } from "@store";
export interface IEscalationPayload {
page_no: number;
page_size: number;
}
export interface IAllEscalationsPayload {
lan: string;
escalationPayload: IEscalationPayload;
}
export const getAllEscalations = (
lan: string,
escalationPayload: IEscalationPayload = {
page_no: 10,
page_size: 0
}
) => (dispatch: AppDispatch) => {
dispatch(setIsLoading(true));
console.log('called getAllEscalations API');
const payload = {
loan_account_number: lan,
...escalationPayload,
}
const url = getApiUrl(ApiKeys.ALL_ESCALATIONS, null, payload );
console.log('getAllEscalationsUrl', url);
return axiosInstance
.get(url)
.then((response) => {
console.log('getAllEscalationsResponse', response);
if (response?.data) {
dispatch(setEscalationData(response.data.data));
dispatch(setPageData(response.data.pages));
}
})
.catch((err) => {
logError(err);
})
.finally(() => {
dispatch(setIsLoading(false));
});
}

View File

@@ -33,6 +33,7 @@ import commitmentTrackerSlice from '@reducers/commitmentTrackerSlice';
import nearbyCasesSlice from '@reducers/nearbyCasesSlice';
import activeCallSlice from '@reducers/activeCallSlice';
import documentsSlice from '@reducers/documentsSlice';
import escalationSlice from '@reducers/escalationSlice';
const rootReducer = combineReducers({
case: caseReducer,
@@ -66,6 +67,7 @@ const rootReducer = combineReducers({
nearbyCasesSlice: nearbyCasesSlice,
activeCall: activeCallSlice,
documentsSlice: documentsSlice,
escalationSlice: escalationSlice,
});
const persistConfig = {