TP-42467 | Tele sensei v3.1 (#815)
* TP-42467 |release 18th jan| Aman Singh * TP-42467 |3.2 half done| Aman Singh * TP-42467 |EM UAT done| Aman Singh * TP-42467 |linting fix| Aman Singh * TP-42467 |linting fix| Aman Singh * TP-42467 |tele sensei done| Aman Singh * TP-42467 |tele sensei done| Aman Singh * TP-42467 |tele sensei done| Aman Singh * TP-42467 |tele sensei done| Aman Singh * TP-42467 |tele sensei done| Aman Singh * TP-42467 |final commit| Aman singh * TP-42467 |lint fix| Aman singh * TP-42467 |before UAT| Aman singh * TP-48182 | UAT Fixes * TP-48182 | UAT Fix * TP-48182 | Resolved PR comments * TP-48182 | Removed Mock Data * TP-48182 | PR comments * TP-57238|tele sensei v3.1 comments resolved| Aman Singh * TP-48182 | Border Radius Removed from header * TP-57238|tele sensei v3.1 comments resolved| Aman Singh * TP-57238|tele sensei v3.1 comments resolved| Aman Singh --------- Co-authored-by: yashmantri <mantri.ramkishor@navi.com> Co-authored-by: Varnit Goyal <varnit.goyal@navi.com>
This commit is contained in:
@@ -89,6 +89,7 @@
|
||||
--light-blue-background: #e5f3ff;
|
||||
--navigation-blue-navigation-content-1: #fcfcfd;
|
||||
--navigation-blue-c2: #caced5;
|
||||
--navi-color-blue-navigation: #001833;
|
||||
|
||||
// black base order
|
||||
--black-base: #1a1a1a;
|
||||
|
||||
@@ -9,6 +9,7 @@ interface ICellRendererShortNumber {
|
||||
hiddenPadding?: number;
|
||||
significantDigits?: number;
|
||||
isCurrency?: boolean;
|
||||
ellipsisWrapperClass?: string;
|
||||
}
|
||||
|
||||
const CellRendererShortNumber: React.FC<ICellRendererShortNumber> = props => {
|
||||
@@ -17,7 +18,8 @@ const CellRendererShortNumber: React.FC<ICellRendererShortNumber> = props => {
|
||||
lineClamp = 1,
|
||||
hiddenPadding = 10,
|
||||
significantDigits = 1,
|
||||
isCurrency = false
|
||||
isCurrency = false,
|
||||
ellipsisWrapperClass
|
||||
} = props;
|
||||
|
||||
if (!Number.isFinite(value)) {
|
||||
@@ -26,7 +28,9 @@ const CellRendererShortNumber: React.FC<ICellRendererShortNumber> = props => {
|
||||
}
|
||||
|
||||
if (!value && value !== 0) {
|
||||
return <EllipsisText text={'-'} lineClamp={lineClamp} />;
|
||||
return (
|
||||
<EllipsisText ellipsisWrapperClass={ellipsisWrapperClass} text={'-'} lineClamp={lineClamp} />
|
||||
);
|
||||
}
|
||||
|
||||
let shorthandNumber = value == 0 ? '0' : shortNumberNotation(value, significantDigits);
|
||||
@@ -37,7 +41,13 @@ const CellRendererShortNumber: React.FC<ICellRendererShortNumber> = props => {
|
||||
if (isCurrency) {
|
||||
shorthandNumber = `₹${shorthandNumber}`;
|
||||
}
|
||||
return <EllipsisText text={shorthandNumber ?? '-'} lineClamp={lineClamp} />;
|
||||
return (
|
||||
<EllipsisText
|
||||
ellipsisWrapperClass={ellipsisWrapperClass}
|
||||
text={shorthandNumber ?? '-'}
|
||||
lineClamp={lineClamp}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (isCurrency) {
|
||||
@@ -48,7 +58,11 @@ const CellRendererShortNumber: React.FC<ICellRendererShortNumber> = props => {
|
||||
return (
|
||||
<Tooltip placement="top" hiddenPadding={hiddenPadding} hideStrategy="referenceHidden">
|
||||
<TooltipTrigger tooltipTriggerClassName="tooltipTriggerWrapper">
|
||||
<EllipsisText text={shorthandNumber ?? '-'} lineClamp={lineClamp} />
|
||||
<EllipsisText
|
||||
ellipsisWrapperClass={ellipsisWrapperClass}
|
||||
text={shorthandNumber ?? '-'}
|
||||
lineClamp={lineClamp}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent
|
||||
className="tooltipWrapper"
|
||||
|
||||
@@ -128,6 +128,7 @@ function SideNavBar({ isDc97User, isHRCChatUser }: ISideNavbarProps) {
|
||||
((percentCompletedCases.paid / percentCompletedCases.total) * 100).toFixed(0)
|
||||
);
|
||||
const hide = HideSideBar.some(path => pathname.includes(path));
|
||||
const isTeleInhouseTeamLead = userData?.roles?.includes(Roles.ROLE_NAVI_TELE_INHOUSE_TEAM_LEAD);
|
||||
|
||||
const disableAmeyoToolbarFlag = window?.config?.DISABLE_AMEYO_TOOLBAR === 'true' || isDc97User;
|
||||
|
||||
@@ -422,7 +423,7 @@ function SideNavBar({ isDc97User, isHRCChatUser }: ISideNavbarProps) {
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{isInternalTeamLead ? (
|
||||
{isTeleInhouseTeamLead ? (
|
||||
<SidebarLinks
|
||||
activeIcon={<AgentsStatusIcon />}
|
||||
inActiveIcon={<AgentsStatusIcon strokeColor="var(--navigation-blue-c2)" />}
|
||||
@@ -489,12 +490,12 @@ function SideNavBar({ isDc97User, isHRCChatUser }: ISideNavbarProps) {
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{isInternalTeamLead ? (
|
||||
{isTeleInhouseTeamLead ? (
|
||||
<SidebarLinks
|
||||
key={APP_ROUTES.AGENT_AVAILABILITY.path}
|
||||
activeIcon={<AvailabilityTrackerIcon />}
|
||||
inActiveIcon={<AvailabilityTrackerIcon strokeColor="var(--navigation-blue-c2)" />}
|
||||
name={'Availablity Tracker'}
|
||||
name={'Availability Tracker'}
|
||||
route={APP_ROUTES.AGENT_AVAILABILITY.path}
|
||||
linkClickHandler={linkClickHandler}
|
||||
currentPathname={pathname}
|
||||
@@ -530,13 +531,13 @@ function SideNavBar({ isDc97User, isHRCChatUser }: ISideNavbarProps) {
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{isInternalTeamLead ? (
|
||||
{isTeleInhouseTeamLead ? (
|
||||
<>
|
||||
<SidebarLinks
|
||||
key={APP_ROUTES.HR_DASHBOARD.path}
|
||||
activeIcon={<PDIcon />}
|
||||
inActiveIcon={<PDIcon fillColor="var(--navigation-blue-c2)" />}
|
||||
name={'Tele Sensei'}
|
||||
name={'Performance Dashboard'}
|
||||
route={APP_ROUTES.SENSEI_TELE.path}
|
||||
linkClickHandler={linkClickHandler}
|
||||
currentPathname={pathname}
|
||||
|
||||
@@ -4,9 +4,11 @@ import {
|
||||
setAgentPerformance,
|
||||
setApiResponse,
|
||||
setDespositionSummary,
|
||||
setEmiBucketWiseSummary,
|
||||
setLoading,
|
||||
setLoadingAgentPerformance,
|
||||
setLoadingDespositionSummary
|
||||
setLoadingDespositionSummary,
|
||||
setLoadingEmiBucketWiseSummary
|
||||
} from '../reducer';
|
||||
|
||||
export const getAgentPerformanceData = () => (dispatch: Dispatch) => {
|
||||
@@ -62,3 +64,19 @@ export const getDespositionSummary = () => (dispatch: Dispatch) => {
|
||||
dispatch(setLoadingDespositionSummary(false));
|
||||
});
|
||||
};
|
||||
|
||||
export const getEMIBucketWiseSummary = () => (dispatch: Dispatch) => {
|
||||
dispatch(setLoadingEmiBucketWiseSummary(true));
|
||||
const url = getApiUrl(ApiKeys.EMI_BUCKET_WISE_SUMMARY);
|
||||
axiosInstance
|
||||
.get(url)
|
||||
.then(response => {
|
||||
dispatch(setEmiBucketWiseSummary(response?.data?.data));
|
||||
})
|
||||
.catch(error => {
|
||||
logError(error, 'emiBucketWiseSummary');
|
||||
})
|
||||
.finally(() => {
|
||||
dispatch(setLoadingEmiBucketWiseSummary(false));
|
||||
});
|
||||
};
|
||||
|
||||
@@ -185,7 +185,7 @@ export const AgentPerformanceColumns = [
|
||||
},
|
||||
{
|
||||
field: 'avgAttemptPerUnpaidCase',
|
||||
headerName: 'Average Calls / Unpaid Case',
|
||||
headerName: 'Average Calls / Unpaid Cases',
|
||||
minWidth: 150,
|
||||
sortable: true,
|
||||
wrapHeaderText: true,
|
||||
|
||||
@@ -44,6 +44,10 @@
|
||||
line-height: 20px;
|
||||
/* 142.857% */
|
||||
letter-spacing: -0.175px;
|
||||
width: -webkit-fill-available !important;
|
||||
width: -moz-available !important;
|
||||
width: -webkit-fill-available !important;
|
||||
width: fill-available !important;
|
||||
}
|
||||
|
||||
.ag-header-group-cell-label {
|
||||
@@ -159,9 +163,11 @@
|
||||
}
|
||||
|
||||
.ag-floating-top {
|
||||
overflow-y: hidden !important;
|
||||
font-weight: 900;
|
||||
color: var(--navi-color-gray-c1) !important;
|
||||
border-bottom: 0px !important;
|
||||
|
||||
.ag-row {
|
||||
background-color: var(--bg-primary) !important;
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
line-height: 20px;
|
||||
/* 142.857% */
|
||||
letter-spacing: -0.175px;
|
||||
width: -webkit-fill-available !important;
|
||||
}
|
||||
|
||||
.ag-header-group-cell-label {
|
||||
@@ -88,6 +89,7 @@
|
||||
}
|
||||
|
||||
.ag-header-row {
|
||||
width: 100% !important;
|
||||
.ag-header-cell {
|
||||
padding-left: 16px;
|
||||
padding-right: 0px;
|
||||
@@ -183,11 +185,15 @@
|
||||
|
||||
.ag-floating-top {
|
||||
font-weight: 900;
|
||||
overflow-y: hidden !important;
|
||||
color: var(--navi-color-gray-c1) !important;
|
||||
border-bottom: 0px !important;
|
||||
.ag-row {
|
||||
background-color: var(--bg-primary) !important;
|
||||
}
|
||||
.ag-floating-top-container {
|
||||
width: -webkit-fill-available !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ag-sort-indicator-icon {
|
||||
@@ -200,5 +206,12 @@
|
||||
.ag-header-cell-text {
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.ag-header-container {
|
||||
width: 100% !important;
|
||||
}
|
||||
.ag-center-cols-viewport {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,6 +147,10 @@ const Index: React.FC<IFilters> = props => {
|
||||
return [data];
|
||||
}, [tableData]);
|
||||
|
||||
useEffect(() => {
|
||||
ref?.current?.api?.sizeColumnsToFit();
|
||||
}, [tableData, loading]);
|
||||
|
||||
return (
|
||||
<div className={cx(styles.agentTableContainer, 'agentPerformance')}>
|
||||
<div className={styles.headerContainer}>
|
||||
@@ -185,6 +189,7 @@ const Index: React.FC<IFilters> = props => {
|
||||
animateRows
|
||||
pinnedTopRowData={pinnedRow}
|
||||
suppressRowClickSelection={true}
|
||||
headerHeight={80}
|
||||
PaginationComponent={
|
||||
<Pagination
|
||||
key={pageSize + pageSize}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
.agentDepositionSummary {
|
||||
.ag-header-viewport {
|
||||
.ag-header-row-column-group {
|
||||
> div:nth-child(1) {
|
||||
> div:nth-child(2) {
|
||||
background-color: var(--green-light);
|
||||
color: var(--green-base);
|
||||
pointer-events: none;
|
||||
@@ -32,9 +32,10 @@
|
||||
line-height: 20px;
|
||||
/* 142.857% */
|
||||
letter-spacing: -0.175px;
|
||||
width: -webkit-fill-available !important;
|
||||
}
|
||||
|
||||
> div:nth-child(2) {
|
||||
> div:nth-child(3) {
|
||||
background-color: var(--pale-yellow);
|
||||
color: var(--navi-color-yellow-dark);
|
||||
pointer-events: none;
|
||||
@@ -72,6 +73,7 @@
|
||||
}
|
||||
|
||||
.ag-header-row {
|
||||
width: 100% !important;
|
||||
.ag-header-cell {
|
||||
padding-left: 16px;
|
||||
padding-right: 0px;
|
||||
@@ -161,6 +163,7 @@
|
||||
}
|
||||
|
||||
.ag-floating-top {
|
||||
overflow-y: hidden !important;
|
||||
font-weight: 900;
|
||||
color: var(--navi-color-gray-c1) !important;
|
||||
border-bottom: 0px !important;
|
||||
@@ -185,5 +188,11 @@
|
||||
.ag-horizontal-left-spacer {
|
||||
visibility: hidden;
|
||||
}
|
||||
.ag-center-cols-viewport {
|
||||
overflow: hidden;
|
||||
}
|
||||
.ag-header-container {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,10 @@ const Index: React.FC<IFilters> = props => {
|
||||
setColumnData(newColumnData);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
ref?.current?.api?.sizeColumnsToFit();
|
||||
}, [tableData, loading]);
|
||||
|
||||
const handlePageChange = (e: number) => {
|
||||
const newParams = { ...params };
|
||||
const pageNumber = e.toString();
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import HorizontalProgress from '@cp/src/components/ProgressBars/horizontalProgress/HorizontalProgress';
|
||||
import React from 'react';
|
||||
import styles from './index.module.scss';
|
||||
import cx from 'classnames';
|
||||
import { formatNumber } from '@cp/src/utils/commonUtils';
|
||||
|
||||
interface ICallOverViewProgressBar {
|
||||
title: string;
|
||||
percentage: number;
|
||||
}
|
||||
|
||||
const CallOverViewProgressBar: React.FC<ICallOverViewProgressBar> = props => {
|
||||
const { title, percentage } = props;
|
||||
return (
|
||||
<div className={styles.numberOfCallsLineChartContainer}>
|
||||
<span className={cx(styles.label, styles.text)}>{title}</span>
|
||||
<HorizontalProgress
|
||||
className={styles.progressColorBackground}
|
||||
percentageClassName={styles.progressColor}
|
||||
percentage={percentage}
|
||||
/>
|
||||
<span className={styles.text}>{formatNumber(percentage, true)}%</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CallOverViewProgressBar;
|
||||
@@ -0,0 +1,89 @@
|
||||
import Dropdown from '@cp/src/components/Dropdown';
|
||||
import HorizontalProgress from '@cp/src/components/ProgressBars/horizontalProgress/HorizontalProgress';
|
||||
import { SelectPickerOptionProps } from '@cp/src/types/CommonConstans';
|
||||
import { readQueryParams } from '@cp/src/utils/QueryParamsHelper';
|
||||
import { formatNumber } from '@cp/src/utils/commonUtils';
|
||||
import { Typography } from '@navi/web-ui/lib/primitives';
|
||||
import cx from 'classnames';
|
||||
import React from 'react';
|
||||
import { AGENT_PERFORMANCE_TABLE, DROPDOWN_OPTIONS } from '../../constants';
|
||||
import { ICallsOverView } from '../../types';
|
||||
import NoDataFoundComponent from './NoDataFoundComponent';
|
||||
import styles from './index.module.scss';
|
||||
import CallOverViewProgressBar from './CallOverViewProgressBar';
|
||||
|
||||
const CallsOverView: React.FC<ICallsOverView> = props => {
|
||||
const { data, updateAndNavigate, params } = props;
|
||||
|
||||
if (!data) {
|
||||
return <NoDataFoundComponent title="Calls Overview" />;
|
||||
}
|
||||
|
||||
const handleSelectionChange = (value: SelectPickerOptionProps) => {
|
||||
if (!value) return;
|
||||
const { [AGENT_PERFORMANCE_TABLE]: updatedParams } = readQueryParams();
|
||||
const newParams = { ...updatedParams };
|
||||
newParams.depositionSummaryCallOverViewFilter = value.value as string;
|
||||
updateAndNavigate(newParams);
|
||||
};
|
||||
|
||||
const { TOTAL_CALLS, VIA_AMEYO, VIA_LONGHORN, VIA_SELF } = data ?? {};
|
||||
|
||||
const longhornPercentage =
|
||||
(Number(
|
||||
VIA_LONGHORN?.[params.depositionSummaryCallOverViewFilter as keyof typeof VIA_LONGHORN]
|
||||
) /
|
||||
Number(
|
||||
TOTAL_CALLS?.[params.depositionSummaryCallOverViewFilter as keyof typeof TOTAL_CALLS]
|
||||
)) *
|
||||
100;
|
||||
|
||||
const ameyoPercentage =
|
||||
(Number(VIA_AMEYO?.[params.depositionSummaryCallOverViewFilter as keyof typeof VIA_AMEYO]) /
|
||||
Number(
|
||||
TOTAL_CALLS?.[params.depositionSummaryCallOverViewFilter as keyof typeof TOTAL_CALLS]
|
||||
)) *
|
||||
100;
|
||||
|
||||
const selfPercentage =
|
||||
(Number(VIA_SELF?.[params.depositionSummaryCallOverViewFilter as keyof typeof VIA_SELF]) /
|
||||
Number(
|
||||
TOTAL_CALLS?.[params.depositionSummaryCallOverViewFilter as keyof typeof TOTAL_CALLS]
|
||||
)) *
|
||||
100;
|
||||
|
||||
return (
|
||||
<div className={styles.ptpOverview}>
|
||||
<div className={styles.headingAndFilter}>
|
||||
<Typography variant="p3" className="font-medium text-[var(--navi-color-gray-c2)]">
|
||||
Calls Overview
|
||||
</Typography>
|
||||
<Dropdown
|
||||
containerClasses={styles.dropdownContainer}
|
||||
innerContainerStyle={styles.dropdownInnerContainer}
|
||||
options={DROPDOWN_OPTIONS}
|
||||
onSelectionChange={handleSelectionChange}
|
||||
defaultSelected={DROPDOWN_OPTIONS.find(
|
||||
item => item.value === params.depositionSummaryCallOverViewFilter
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className={cx(styles.titleContainer)}>
|
||||
<div
|
||||
className={cx({
|
||||
[styles.pieChart]: true,
|
||||
pieChartContainerClass: true
|
||||
})}
|
||||
>
|
||||
<div className={cx(styles.pieChartContainer, styles.callsOverviewHeight)}>
|
||||
<CallOverViewProgressBar title="Longhorn" percentage={longhornPercentage} />
|
||||
<CallOverViewProgressBar title="Ameyo" percentage={ameyoPercentage} />
|
||||
<CallOverViewProgressBar title="Self" percentage={selfPercentage} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CallsOverView;
|
||||
@@ -0,0 +1,22 @@
|
||||
import NoDataFound from '@cp/src/assets/icons/NoDataFound';
|
||||
import { Typography } from '@navi/web-ui/lib/primitives';
|
||||
import styles from './index.module.scss';
|
||||
import React from 'react';
|
||||
|
||||
interface NoDataFoundComponentProps {
|
||||
title: string;
|
||||
}
|
||||
|
||||
const NoDataFoundComponent: React.FC<NoDataFoundComponentProps> = props => {
|
||||
const { title } = props;
|
||||
return (
|
||||
<div className={styles.emptyView}>
|
||||
<div className={styles.headingAndFilter}>
|
||||
<Typography variant="p3">{title}</Typography>
|
||||
</div>
|
||||
<NoDataFound className={styles.noDataFoundIcon} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default NoDataFoundComponent;
|
||||
@@ -0,0 +1,117 @@
|
||||
import Highcharts from 'highcharts';
|
||||
import HighchartsReact from 'highcharts-react-official';
|
||||
import React from 'react';
|
||||
import { formatNumber, pluralisation } from 'src/utils/commonUtils';
|
||||
import styles from './index.module.scss';
|
||||
import { Typography } from '@navi/web-ui/lib/primitives';
|
||||
import { summaryGroup, summaryGroupColorMapping } from '../../constants';
|
||||
import NoDataFoundComponent from './NoDataFoundComponent';
|
||||
import { CashEarnedChartHCProps, responseDataType } from '../../types';
|
||||
|
||||
const transformData = (responseData: responseDataType) => {
|
||||
const data = [];
|
||||
let key: keyof typeof responseData;
|
||||
for (key in responseData) {
|
||||
data.push({
|
||||
name: summaryGroup[key as keyof typeof summaryGroup],
|
||||
y: responseData[key],
|
||||
value: responseData[key],
|
||||
color: summaryGroupColorMapping[key as keyof typeof summaryGroupColorMapping],
|
||||
formattedValue: formatNumber(responseData[key] as number, false)
|
||||
});
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
const getSum = (data: any) => {
|
||||
let sum = 0;
|
||||
let key: keyof typeof data;
|
||||
for (key in data) {
|
||||
sum += Number.isInteger(data[key]) ? data[key] : 0;
|
||||
}
|
||||
return sum;
|
||||
};
|
||||
const NumberOfCases: React.FC<CashEarnedChartHCProps> = props => {
|
||||
const { dataTObeFed } = props;
|
||||
|
||||
if (!dataTObeFed) {
|
||||
return <NoDataFoundComponent title="Number of Cases" />;
|
||||
}
|
||||
|
||||
const sum = getSum(dataTObeFed);
|
||||
|
||||
const options = {
|
||||
chart: {
|
||||
plotBackgroundColor: null,
|
||||
plotBorderWidth: 0,
|
||||
plotShadow: false,
|
||||
style: {
|
||||
fontFamily: 'Inter'
|
||||
},
|
||||
renderTo: 'container',
|
||||
height: 215,
|
||||
width: 500
|
||||
},
|
||||
credits: {
|
||||
enabled: false
|
||||
},
|
||||
title: {
|
||||
text: `<div class='${styles.pieChartCenter}'>${formatNumber(sum)}<br><span class=${
|
||||
styles.pieChartSubtext
|
||||
}>Total ${pluralisation('Case', sum, 's')}<span></div>`,
|
||||
align: 'center',
|
||||
verticalAlign: 'middle'
|
||||
},
|
||||
tooltip: {
|
||||
enabled: false
|
||||
},
|
||||
accessibility: {
|
||||
point: {
|
||||
valueSuffix: '%'
|
||||
}
|
||||
},
|
||||
plotOptions: {
|
||||
pie: {
|
||||
size: 160,
|
||||
animation: true,
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
allowOverlap: true,
|
||||
align: 'left',
|
||||
format: `<div class=${styles.barChartLabel}>{point.name}</div><div class=${styles.barchartLabelNumber}>{point.formattedValue} <span class=${styles.percentage}>({point.percentage:.1f}%)</span></div>`,
|
||||
useHTML: true,
|
||||
distance: 20,
|
||||
filter: {
|
||||
property: 'percentage',
|
||||
operator: '>',
|
||||
value: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
name: 'CashEarned',
|
||||
innerSize: '70%',
|
||||
data: transformData(dataTObeFed)
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.ptpOverview}>
|
||||
<div className={styles.headingAndFilter}>
|
||||
<Typography variant="p3" className="font-medium text-[var(--navi-color-gray-c2)]">
|
||||
Number of cases
|
||||
</Typography>
|
||||
</div>
|
||||
<div className={'pieChartContainerClass'}>
|
||||
<div className={styles.pieChartContainer}>
|
||||
<HighchartsReact highcharts={Highcharts} options={options} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default NumberOfCases;
|
||||
@@ -0,0 +1,159 @@
|
||||
import Highcharts from 'highcharts';
|
||||
import HighchartsReact from 'highcharts-react-official';
|
||||
import React from 'react';
|
||||
import styles from './index.module.scss';
|
||||
import cx from 'classnames';
|
||||
import Dropdown from '@cp/src/components/Dropdown';
|
||||
import { readQueryParams } from '@cp/src/utils/QueryParamsHelper';
|
||||
import { Typography } from '@navi/web-ui/lib/primitives';
|
||||
import { AGENT_PERFORMANCE_TABLE, DROPDOWN_OPTIONS } from '../../constants';
|
||||
import { IPTPOverView } from '../../types';
|
||||
import NoDataFoundComponent from './NoDataFoundComponent';
|
||||
import { formatNumber } from '@cp/src/utils/commonUtils';
|
||||
|
||||
const PTPOverView: React.FC<IPTPOverView> = props => {
|
||||
const { data, params, updateAndNavigate } = props;
|
||||
|
||||
if (!data) {
|
||||
return <NoDataFoundComponent title="PTP Overview" />;
|
||||
}
|
||||
const { PTP_GENERATED, PTP_CONVERTED, BROKEN_PTP, FUTURE_PTP } = data;
|
||||
|
||||
const handleSelectionChange = (value: any) => {
|
||||
if (!value) return;
|
||||
const { [AGENT_PERFORMANCE_TABLE]: updatedParams } = readQueryParams();
|
||||
const newParams = { ...updatedParams };
|
||||
newParams.depositionSummaryPTPOverViewFilter = value.value as string;
|
||||
updateAndNavigate(newParams);
|
||||
};
|
||||
|
||||
const dataToBeFed = [
|
||||
{
|
||||
name: 'PTP Converted',
|
||||
y: Number(
|
||||
PTP_CONVERTED[params.depositionSummaryPTPOverViewFilter as keyof typeof PTP_CONVERTED]
|
||||
),
|
||||
value: Number(
|
||||
PTP_CONVERTED[params.depositionSummaryPTPOverViewFilter as keyof typeof PTP_CONVERTED]
|
||||
),
|
||||
color: '#5D87FF',
|
||||
formattedValue: formatNumber(
|
||||
Number(
|
||||
PTP_CONVERTED[params.depositionSummaryPTPOverViewFilter as keyof typeof PTP_CONVERTED]
|
||||
),
|
||||
true
|
||||
)
|
||||
},
|
||||
{
|
||||
name: 'Broken PTP',
|
||||
y: Number(BROKEN_PTP[params.depositionSummaryPTPOverViewFilter as keyof typeof BROKEN_PTP]),
|
||||
value: Number(
|
||||
BROKEN_PTP[params.depositionSummaryPTPOverViewFilter as keyof typeof BROKEN_PTP]
|
||||
),
|
||||
color: '#6FE8C8',
|
||||
formattedValue: formatNumber(
|
||||
Number(BROKEN_PTP[params.depositionSummaryPTPOverViewFilter as keyof typeof BROKEN_PTP]),
|
||||
true
|
||||
)
|
||||
},
|
||||
{
|
||||
name: 'Future PTP',
|
||||
y: Number(FUTURE_PTP[params.depositionSummaryPTPOverViewFilter as keyof typeof FUTURE_PTP]),
|
||||
value: Number(
|
||||
FUTURE_PTP[params.depositionSummaryPTPOverViewFilter as keyof typeof FUTURE_PTP]
|
||||
),
|
||||
color: '#FA896B',
|
||||
formattedValue: formatNumber(
|
||||
Number(FUTURE_PTP[params.depositionSummaryPTPOverViewFilter as keyof typeof FUTURE_PTP]),
|
||||
true
|
||||
)
|
||||
}
|
||||
];
|
||||
const options = {
|
||||
chart: {
|
||||
plotBackgroundColor: null,
|
||||
plotBorderWidth: 0,
|
||||
plotShadow: false,
|
||||
style: {
|
||||
fontFamily: 'Inter'
|
||||
},
|
||||
renderTo: 'container',
|
||||
height: 225,
|
||||
width: 500
|
||||
},
|
||||
credits: {
|
||||
enabled: false
|
||||
},
|
||||
title: {
|
||||
text: `<div>
|
||||
<div class='${styles.chartTitleContainer}'>${formatNumber(
|
||||
Number(
|
||||
PTP_GENERATED[params.depositionSummaryPTPOverViewFilter as keyof typeof PTP_GENERATED]
|
||||
)
|
||||
)}</div>
|
||||
</div>`,
|
||||
align: 'center',
|
||||
verticalAlign: 'middle'
|
||||
},
|
||||
tooltip: {
|
||||
enabled: false
|
||||
},
|
||||
accessibility: {
|
||||
point: {
|
||||
valueSuffix: '%'
|
||||
}
|
||||
},
|
||||
plotOptions: {
|
||||
pie: {
|
||||
size: 160,
|
||||
animation: true,
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
allowOverlap: true,
|
||||
align: 'left',
|
||||
format: `<div class=${styles.barChartLabel}>{point.name}</div><div class=${styles.barchartLabelNumber}>{point.formattedValue}</div>`,
|
||||
useHTML: true,
|
||||
distance: 10,
|
||||
filter: {
|
||||
property: 'percentage',
|
||||
operator: '>',
|
||||
value: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
name: 'CashEarned',
|
||||
innerSize: '70%',
|
||||
data: dataToBeFed
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={cx(styles.ptpOverview, styles.mb0)}>
|
||||
<div className={styles.headingAndFilter}>
|
||||
<Typography variant="p3" className="font-medium text-[var(--navi-color-gray-c2)]">
|
||||
PTPs Overview
|
||||
</Typography>
|
||||
<Dropdown
|
||||
containerClasses={styles.dropdownContainer}
|
||||
innerContainerStyle={styles.dropdownInnerContainer}
|
||||
options={DROPDOWN_OPTIONS}
|
||||
onSelectionChange={handleSelectionChange}
|
||||
defaultSelected={DROPDOWN_OPTIONS.find(
|
||||
item => item.value === params.depositionSummaryPTPOverViewFilter
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className={'pieChartContainerClass'}>
|
||||
<div className={styles.pieChartContainer}>
|
||||
<HighchartsReact highcharts={Highcharts} options={options} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default PTPOverView;
|
||||
@@ -0,0 +1,186 @@
|
||||
import { ICellRendererParams } from 'ag-grid-community';
|
||||
import styles from './index.module.scss';
|
||||
import TableCellRenderer from '@cp/src/components/TableCellRenderer';
|
||||
import CellRendererShortNumber from '@cp/src/components/TableCellRenderer/CellRendererShortNumber';
|
||||
import cx from 'classnames';
|
||||
import { shortNumberNotation } from '@cp/src/utils/commonUtils';
|
||||
|
||||
export const AgentPerformanceColumns = [
|
||||
{
|
||||
headerName: '',
|
||||
children: [
|
||||
{
|
||||
field: 'name',
|
||||
headerName: '',
|
||||
minWidth: 280,
|
||||
pinned: 'left',
|
||||
cellClass: (params: ICellRendererParams) => {
|
||||
return cx({ [styles.bold]: params?.data?.bold }, styles.border, {
|
||||
[styles.blueBackground]: params?.data?.blue
|
||||
});
|
||||
},
|
||||
suppressMovable: true,
|
||||
cellRenderer: (params: ICellRendererParams) => {
|
||||
const { name } = params.data || {};
|
||||
return (
|
||||
<TableCellRenderer
|
||||
ellipsisWrapperClass={cx({ [styles.subPoint]: params?.data?.subPoint })}
|
||||
value={name}
|
||||
showToolTip
|
||||
toolTipContent={name}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
headerName: 'Bucket Range',
|
||||
children: [
|
||||
{
|
||||
field: '<4k',
|
||||
headerName: 'Less than 4k',
|
||||
width: 160,
|
||||
autoHeaderHeight: true,
|
||||
wrapHeaderText: true,
|
||||
cellClass: (params: ICellRendererParams) => {
|
||||
return cx({ [styles.blueBackground]: params?.data?.blue });
|
||||
},
|
||||
cellRenderer: (params: ICellRendererParams) => {
|
||||
const data = params.data?.['<4k'];
|
||||
const isCurrency = params.data?.isCurrency;
|
||||
const isPercentage = params.data?.percentage;
|
||||
const value = shortNumberNotation(data, 2) + '%';
|
||||
if (isPercentage) {
|
||||
return (
|
||||
<TableCellRenderer
|
||||
ellipsisWrapperClass={cx({ [styles.subPointInternal]: params?.data?.subPoint })}
|
||||
value={value}
|
||||
showToolTip
|
||||
toolTipContent={value}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<CellRendererShortNumber
|
||||
ellipsisWrapperClass={cx({
|
||||
[styles.bold]: params?.data?.bold,
|
||||
[styles.subPointInternal]: params?.data?.subPoint
|
||||
})}
|
||||
value={data}
|
||||
isCurrency={isCurrency}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
field: '4k-7k',
|
||||
wrapHeaderText: true,
|
||||
headerName: '4k to 7k',
|
||||
autoHeaderHeight: true,
|
||||
width: 120,
|
||||
cellClass: (params: ICellRendererParams) => {
|
||||
return cx({ [styles.blueBackground]: params?.data?.blue });
|
||||
},
|
||||
cellRenderer: (params: ICellRendererParams) => {
|
||||
const data = params.data?.['4k-7k'];
|
||||
const isPercentage = params.data?.percentage;
|
||||
const isCurrency = params.data?.isCurrency;
|
||||
const value = shortNumberNotation(data, 2) + '%';
|
||||
if (isPercentage) {
|
||||
return (
|
||||
<TableCellRenderer
|
||||
ellipsisWrapperClass={cx({ [styles.subPointInternal]: params?.data?.subPoint })}
|
||||
value={value}
|
||||
showToolTip
|
||||
toolTipContent={value}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<CellRendererShortNumber
|
||||
ellipsisWrapperClass={cx({
|
||||
[styles.bold]: params?.data?.bold,
|
||||
[styles.subPointInternal]: params?.data?.subPoint
|
||||
})}
|
||||
isCurrency={isCurrency}
|
||||
value={data}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
field: '7k-10k',
|
||||
wrapHeaderText: true,
|
||||
headerName: '7k to 10k',
|
||||
autoHeaderHeight: true,
|
||||
width: 120,
|
||||
cellClass: (params: ICellRendererParams) => {
|
||||
return cx({ [styles.blueBackground]: params?.data?.blue });
|
||||
},
|
||||
cellRenderer: (params: ICellRendererParams) => {
|
||||
const data = params.data?.['7k-10k'];
|
||||
const isPercentage = params.data?.percentage;
|
||||
const isCurrency = params.data?.isCurrency;
|
||||
const value = shortNumberNotation(data, 2) + '%';
|
||||
if (isPercentage) {
|
||||
return (
|
||||
<TableCellRenderer
|
||||
ellipsisWrapperClass={cx({ [styles.subPointInternal]: params?.data?.subPoint })}
|
||||
value={value}
|
||||
showToolTip
|
||||
toolTipContent={value}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<CellRendererShortNumber
|
||||
ellipsisWrapperClass={cx({
|
||||
[styles.bold]: params?.data?.bold,
|
||||
[styles.subPointInternal]: params?.data?.subPoint
|
||||
})}
|
||||
isCurrency={isCurrency}
|
||||
value={data}
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
field: '10k+',
|
||||
wrapHeaderText: true,
|
||||
headerName: 'More than 10k',
|
||||
autoHeaderHeight: true,
|
||||
cellClass: (params: ICellRendererParams) => {
|
||||
return cx({ [styles.blueBackground]: params?.data?.blue });
|
||||
},
|
||||
width: 160,
|
||||
cellRenderer: (params: ICellRendererParams) => {
|
||||
const data = params.data?.['10k+'];
|
||||
const isPercentage = params.data?.percentage;
|
||||
const isCurrency = params.data?.isCurrency;
|
||||
const value = shortNumberNotation(data, 2) + '%';
|
||||
if (isPercentage) {
|
||||
return (
|
||||
<TableCellRenderer
|
||||
ellipsisWrapperClass={cx({ [styles.subPointInternal]: params?.data?.subPoint })}
|
||||
value={value}
|
||||
showToolTip
|
||||
toolTipContent={value}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<CellRendererShortNumber
|
||||
ellipsisWrapperClass={cx({
|
||||
[styles.bold]: params?.data?.bold,
|
||||
[styles.subPointInternal]: params?.data?.subPoint
|
||||
})}
|
||||
isCurrency={isCurrency}
|
||||
value={data}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
@@ -0,0 +1,388 @@
|
||||
.EmiBucketWiseSummary {
|
||||
position: relative;
|
||||
margin-top: 120px;
|
||||
|
||||
.tableContainer {
|
||||
.tableActions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
// padding-right: 32px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.border {
|
||||
border-right: 1px solid var(--navi-color-gray-border) !important;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.blueBackground {
|
||||
background-color: var(--bg-blue);
|
||||
}
|
||||
|
||||
.dataContainer {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
|
||||
.tableContainer {
|
||||
position: relative;
|
||||
flex-basis: 66%;
|
||||
box-shadow: 0px 8px 20px 0px rgba(221, 221, 221, 0.3);
|
||||
.noDataFound {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.subPoint {
|
||||
margin-left: 20px;
|
||||
color: var(--navi-color-gray-c2);
|
||||
font-size: 13px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
letter-spacing: -0.13px;
|
||||
}
|
||||
|
||||
.subPointInternal {
|
||||
color: var(--navi-color-gray-c2);
|
||||
font-size: 13px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
letter-spacing: -0.13px;
|
||||
}
|
||||
|
||||
.mb0 {
|
||||
margin-bottom: 0px !important;
|
||||
}
|
||||
|
||||
.ptpOverview {
|
||||
margin-bottom: 24px;
|
||||
background: white;
|
||||
padding-bottom: 32px;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0px 8px 20px 0px rgba(221, 221, 221, 0.3);
|
||||
height: 252px;
|
||||
.headingAndFilter {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
border-radius: 8px 8px 0px 0px;
|
||||
border: 0px solid var(--navi-color-gray-border);
|
||||
background: #f1f2f4;
|
||||
padding: 0px 16px;
|
||||
margin-bottom: 12px;
|
||||
height: 44px;
|
||||
|
||||
.heading {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
line-height: 28px;
|
||||
letter-spacing: -0.25px;
|
||||
color: var(--navi-color-gray-c1);
|
||||
}
|
||||
|
||||
.dropdownContainer {
|
||||
width: 150px;
|
||||
|
||||
.dropdownInnerContainer {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--navi-color-gray-border);
|
||||
background: var(--navi-color-gray-bg-primary);
|
||||
padding: 4px 12.5px;
|
||||
box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.emptyView {
|
||||
width: 500px;
|
||||
height: 252px;
|
||||
margin-bottom: 24px;
|
||||
background: white;
|
||||
padding: 16px 20px 16px 20px;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0px 8px 20px 0px rgba(221, 221, 221, 0.3);
|
||||
position: relative;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.headingAndFilter {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.noDataFoundIcon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
|
||||
.barChartLabel {
|
||||
color: var(--navi-color-gray-c2);
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 18px;
|
||||
letter-spacing: -0.12px;
|
||||
}
|
||||
|
||||
.barchartLabelNumber {
|
||||
color: var(--navi-color-blue-navigation);
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 12px;
|
||||
/* 100% */
|
||||
letter-spacing: -0.12px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.pieChartCenter {
|
||||
color: var(--navi-color-gray-c3);
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 20px;
|
||||
letter-spacing: -0.175px;
|
||||
}
|
||||
|
||||
.pieChartSubtext {
|
||||
color: var(--navi-color-gray-c3);
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 20px;
|
||||
letter-spacing: -0.175px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.progressColorBackground {
|
||||
background-color: var(--grayscale-6);
|
||||
height: 12px;
|
||||
width: 305px;
|
||||
}
|
||||
|
||||
.progressColor {
|
||||
background-color: var(--green-base);
|
||||
transition: width 400ms ease-in-out;
|
||||
}
|
||||
|
||||
.percentage {
|
||||
color: var(--navi-color-gray-c3);
|
||||
}
|
||||
|
||||
.numberOfCallsLineChartContainer {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
|
||||
.label {
|
||||
flex-basis: 15%;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.text {
|
||||
color: var(--navi-color-gray-c2);
|
||||
text-align: right;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 18px;
|
||||
letter-spacing: -0.12px;
|
||||
}
|
||||
}
|
||||
|
||||
.pieChartContainer {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
flex-direction: column;
|
||||
}
|
||||
.callsOverviewHeight {
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
.fb32 {
|
||||
flex-basis: 32%;
|
||||
}
|
||||
|
||||
:global {
|
||||
.agentDepositionSummary {
|
||||
.ag-header-viewport {
|
||||
.ag-header-row-column-group {
|
||||
> div:nth-child(1) {
|
||||
background-color: var(--pale-yellow);
|
||||
color: var(--navi-color-yellow-dark);
|
||||
pointer-events: none;
|
||||
text-align: center;
|
||||
font-family: Inter;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
/* 142.857% */
|
||||
letter-spacing: -0.175px;
|
||||
}
|
||||
|
||||
.ag-header-group-cell-label {
|
||||
flex: none;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
letter-spacing: -0.175px;
|
||||
}
|
||||
}
|
||||
|
||||
.ag-pinned-left-cols-container {
|
||||
.ag-cell {
|
||||
padding-right: 5px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ag-header-row {
|
||||
.ag-header-cell {
|
||||
padding-left: 16px;
|
||||
padding-right: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.ag-row {
|
||||
.ag-cell {
|
||||
padding-left: 16px;
|
||||
padding-right: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.ag-pinned-left-header {
|
||||
.ag-header-cell {
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.ag-header-group-cell {
|
||||
background-color: unset !important;
|
||||
padding-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.ag-center-cols-clipper {
|
||||
min-height: unset !important;
|
||||
}
|
||||
|
||||
.ag-header-group-cell {
|
||||
border-right: 1px solid var(--greyscale-light);
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.ag-header-group-cell-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.ag-header-group-cell {
|
||||
.ag-header-group-text {
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
:nth-child(1) {
|
||||
display: inline-block;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.paginationWrapperClasses {
|
||||
overflow: unset;
|
||||
z-index: var(--z-index-pagination-wrapper);
|
||||
bottom: 4px;
|
||||
|
||||
> div:nth-child(1) {
|
||||
border-bottom-left-radius: 8px;
|
||||
border-bottom-right-radius: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.customHeaderManagement {
|
||||
width: 140px;
|
||||
text-align: center;
|
||||
|
||||
.ag-header-cell-comp-wrapper {
|
||||
.ag-header-cell-label {
|
||||
display: grid;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
text-overflow: inherit;
|
||||
text-wrap: wrap;
|
||||
width: 42px; // according to figma width
|
||||
}
|
||||
}
|
||||
|
||||
.ag-react-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ag-floating-top {
|
||||
font-weight: 900;
|
||||
overflow-y: hidden !important;
|
||||
color: var(--navi-color-gray-c1) !important;
|
||||
border-bottom: 0px !important;
|
||||
|
||||
.ag-row {
|
||||
background-color: var(--bg-primary) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ag-sort-indicator-icon {
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.ag-row-last {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
.ag-header-cell-text {
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.ag-horizontal-left-spacer {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.pieChartContainerClass {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
275
src/pages/SenseiTele/components/emiBucketWiseSummary/index.tsx
Normal file
275
src/pages/SenseiTele/components/emiBucketWiseSummary/index.tsx
Normal file
@@ -0,0 +1,275 @@
|
||||
import Download from '@cp/src/assets/images/icons/Download';
|
||||
import Loader from '@cp/src/components/Loader/Loader';
|
||||
import { RootState } from '@cp/src/store';
|
||||
import { DateFormat, dateFormat } from '@cp/src/utils/DateHelper';
|
||||
import { AgTable } from '@navi/web-ui/lib/components';
|
||||
import { Button, Typography } from '@navi/web-ui/lib/primitives';
|
||||
import { SortChangedEvent } from 'ag-grid-community';
|
||||
import { AgGridReact } from 'ag-grid-react';
|
||||
import cx from 'classnames';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { IBuckerrWiseSummarySum, IEMIBucketWiseSummary, IFilters } from '../../types';
|
||||
import { AgentPerformanceColumns } from './columnDef';
|
||||
import styles from './index.module.scss';
|
||||
import {
|
||||
SUMMARY_GROUP,
|
||||
emiBucketWiseRowsEnum,
|
||||
generateFinalSummaryGroup,
|
||||
getRowObject,
|
||||
IEmiBucketWiseDataObject
|
||||
} from '../../constants';
|
||||
import NumberOfCases from './NumberOfCases';
|
||||
import CallsOverView from './CallsOverView';
|
||||
import PTPOverView from './PtpOverview';
|
||||
import NoDataFound from '@cp/src/assets/icons/NoDataFound';
|
||||
import { l } from 'msw/lib/core/GraphQLHandler-d4787f91';
|
||||
|
||||
const Index: React.FC<IFilters> = props => {
|
||||
const { params, updateAndNavigate, url } = props;
|
||||
const ref = useRef<AgGridReact<any>>(null);
|
||||
const [columnData, setColumnData] = React.useState(AgentPerformanceColumns);
|
||||
const [dataObject, setDataObject] = React.useState<IEmiBucketWiseDataObject>();
|
||||
const tableData = useSelector((state: RootState) => state.teleSensei.emiBucketWiseSummaryFilter);
|
||||
const loading = useSelector((state: RootState) => state.teleSensei.loadingDespositionSummary);
|
||||
const [data, setData] = React.useState<Array<any>>([]);
|
||||
const dispatch = useDispatch();
|
||||
const handleSort = (e: SortChangedEvent<IEMIBucketWiseSummary[]>) => {
|
||||
if (e?.source === 'gridOptionsChanged') return;
|
||||
const newParams = { ...params };
|
||||
const sortModel = e?.columnApi?.getColumnState();
|
||||
const sortedColumns = sortModel?.find(item => item.sort !== null);
|
||||
if (!sortedColumns) {
|
||||
delete newParams?.sortColumnDisposition;
|
||||
delete newParams?.sortOrderDisposition;
|
||||
newParams.pageNoDisposition = '1';
|
||||
updateAndNavigate(newParams);
|
||||
ref?.current?.api.paginationGoToPage(0);
|
||||
return;
|
||||
}
|
||||
const { colId, sort } = sortedColumns;
|
||||
newParams.sortColumnDisposition = colId;
|
||||
newParams.sortOrderDisposition = sort as string;
|
||||
newParams.pageNoDisposition = '1';
|
||||
ref?.current?.api.paginationGoToPage(0);
|
||||
updateAndNavigate(newParams);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!params?.sortColumnDisposition) {
|
||||
setColumnData(AgentPerformanceColumns);
|
||||
}
|
||||
const newColumnData = AgentPerformanceColumns.map(item => {
|
||||
const children = item.children?.map(child => {
|
||||
if (child.field === params?.sortColumnDisposition) {
|
||||
return {
|
||||
...child,
|
||||
sort: params?.sortOrderDisposition as any
|
||||
};
|
||||
}
|
||||
return child;
|
||||
});
|
||||
return {
|
||||
...item,
|
||||
children
|
||||
};
|
||||
});
|
||||
setColumnData(newColumnData);
|
||||
}, []);
|
||||
|
||||
const handleDownloadReport = () => {
|
||||
ref?.current?.api?.exportDataAsCsv({
|
||||
fileName: `EMI-Bucket-Wise-Summary-${dateFormat(new Date(), DateFormat.FILE_DATE_FORMAT)}`
|
||||
});
|
||||
};
|
||||
|
||||
const generateData = () => {
|
||||
const allBucketWiseSummary = tableData?.flatMap(item => item.bucketWiseSummary);
|
||||
const allData: IEmiBucketWiseDataObject = getRowObject();
|
||||
const finalSummaryGroup = generateFinalSummaryGroup();
|
||||
if (!allBucketWiseSummary.length) {
|
||||
setData([]);
|
||||
setDataObject(null);
|
||||
return;
|
||||
}
|
||||
let coverageUnpaidCases4k = 0;
|
||||
let coverageUnpaidCases7k = 0;
|
||||
let coverageUnpaidCases10k = 0;
|
||||
let coverageUnpaidCases4k7k = 0;
|
||||
|
||||
let avgUnpaidCases4k = 0;
|
||||
let avgUnpaidCases7k = 0;
|
||||
let avgUnpaidCases10k = 0;
|
||||
let avgUnpaidCases4k7k = 0;
|
||||
|
||||
for (const item of allBucketWiseSummary) {
|
||||
const { bucketGroup } = item;
|
||||
let key: keyof typeof finalSummaryGroup;
|
||||
switch (bucketGroup) {
|
||||
case '<4k':
|
||||
for (key in item) {
|
||||
finalSummaryGroup['<4k'][key as IBuckerrWiseSummarySum] +=
|
||||
item[key as keyof typeof item];
|
||||
}
|
||||
coverageUnpaidCases4k += item.unpaidCases ?? 0 * item.unpaidCasesCoverage ?? 0;
|
||||
avgUnpaidCases4k += item.averageUniqueDaysCalledPerUnpaidCases * item.unpaidCases ?? 0;
|
||||
break;
|
||||
case '4k-7k':
|
||||
for (key in item) {
|
||||
finalSummaryGroup['4k-7k'][key as IBuckerrWiseSummarySum] +=
|
||||
item[key as keyof typeof item];
|
||||
}
|
||||
coverageUnpaidCases4k7k += item.unpaidCases ?? 0 * item.unpaidCasesCoverage ?? 0;
|
||||
avgUnpaidCases4k7k += item.averageUniqueDaysCalledPerUnpaidCases * item.unpaidCases ?? 0;
|
||||
break;
|
||||
case '7k-10k':
|
||||
for (key in item) {
|
||||
finalSummaryGroup['7k-10k'][key as IBuckerrWiseSummarySum] +=
|
||||
item[key as keyof typeof item];
|
||||
}
|
||||
coverageUnpaidCases7k += item.unpaidCases ?? 0 * item.unpaidCasesCoverage ?? 0;
|
||||
avgUnpaidCases7k += item.averageUniqueDaysCalledPerUnpaidCases * item.unpaidCases ?? 0;
|
||||
break;
|
||||
case '10k+':
|
||||
for (key in item) {
|
||||
finalSummaryGroup['10k+'][key as IBuckerrWiseSummarySum] +=
|
||||
item[key as keyof typeof item];
|
||||
}
|
||||
coverageUnpaidCases10k += item.unpaidCases ?? 0 * item.unpaidCasesCoverage ?? 0;
|
||||
avgUnpaidCases10k += item.averageUniqueDaysCalledPerUnpaidCases * item.unpaidCases ?? 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (const allDataKey in allData) {
|
||||
for (const summaryGroupKey in SUMMARY_GROUP) {
|
||||
const rightHandSideKey = allData[allDataKey as keyof typeof allData].key;
|
||||
allData[allDataKey][SUMMARY_GROUP[summaryGroupKey]] =
|
||||
finalSummaryGroup[SUMMARY_GROUP[summaryGroupKey]][rightHandSideKey];
|
||||
}
|
||||
}
|
||||
|
||||
// EMI CE % calculation
|
||||
allData[emiBucketWiseRowsEnum.EMI_CE] = {
|
||||
...allData[emiBucketWiseRowsEnum.EMI_CE],
|
||||
'<4k': (finalSummaryGroup['<4k'].emiCollected / finalSummaryGroup['<4k'].emiAllocated) * 100,
|
||||
'4k-7k':
|
||||
(finalSummaryGroup['4k-7k'].emiCollected / finalSummaryGroup['4k-7k'].emiAllocated) * 100,
|
||||
'7k-10k':
|
||||
(finalSummaryGroup['7k-10k'].emiCollected / finalSummaryGroup['7k-10k'].emiAllocated) * 100,
|
||||
'10k+':
|
||||
(finalSummaryGroup['10k+'].emiCollected / finalSummaryGroup['10k+'].emiAllocated) * 100
|
||||
};
|
||||
|
||||
//Calculation for coverage on unpaid cases
|
||||
allData[emiBucketWiseRowsEnum.COVERAGE_UNPAID_CASES] = {
|
||||
...allData[emiBucketWiseRowsEnum.COVERAGE_UNPAID_CASES],
|
||||
'<4k':
|
||||
(finalSummaryGroup['<4k'].unpaidCasesCovered / finalSummaryGroup['<4k'].unpaidCases) * 100,
|
||||
'4k-7k':
|
||||
(finalSummaryGroup['4k-7k'].unpaidCasesCovered / finalSummaryGroup['4k-7k'].unpaidCases) *
|
||||
100,
|
||||
'7k-10k':
|
||||
(finalSummaryGroup['7k-10k'].unpaidCasesCovered / finalSummaryGroup['7k-10k'].unpaidCases) *
|
||||
100,
|
||||
'10k+':
|
||||
(finalSummaryGroup['10k+'].unpaidCasesCovered / finalSummaryGroup['10k+'].unpaidCases) * 100
|
||||
};
|
||||
|
||||
allData[emiBucketWiseRowsEnum.AVG_CALLS_UNPAID_CASES] = {
|
||||
...allData[emiBucketWiseRowsEnum.AVG_CALLS_UNPAID_CASES],
|
||||
'<4k': finalSummaryGroup['<4k'].totalCalls / coverageUnpaidCases4k,
|
||||
'4k-7k': finalSummaryGroup['4k-7k'].totalCalls / coverageUnpaidCases4k7k,
|
||||
'7k-10k': finalSummaryGroup['7k-10k'].totalCalls / coverageUnpaidCases7k,
|
||||
'10k+': finalSummaryGroup['10k+'].totalCalls / coverageUnpaidCases10k
|
||||
};
|
||||
|
||||
allData[emiBucketWiseRowsEnum.AVG_UNIQUE_DAYS_CALLED_UNPAID_CASES] = {
|
||||
...allData[emiBucketWiseRowsEnum.AVG_UNIQUE_DAYS_CALLED_UNPAID_CASES],
|
||||
'<4k': avgUnpaidCases4k / finalSummaryGroup['<4k'].unpaidCases,
|
||||
'4k-7k': avgUnpaidCases4k7k / finalSummaryGroup['4k-7k'].unpaidCases,
|
||||
'7k-10k': avgUnpaidCases7k / finalSummaryGroup['7k-10k'].unpaidCases,
|
||||
'10k+': avgUnpaidCases10k / finalSummaryGroup['10k+'].unpaidCases
|
||||
};
|
||||
|
||||
const totalCases = Object.values({ ...allData });
|
||||
setData(totalCases);
|
||||
setDataObject(allData);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
generateData();
|
||||
}, [tableData]);
|
||||
|
||||
useEffect(() => {
|
||||
ref?.current?.api?.sizeColumnsToFit();
|
||||
}, [tableData, loading]);
|
||||
|
||||
return (
|
||||
<div className={cx(styles.EmiBucketWiseSummary, 'agentDepositionSummary')}>
|
||||
<div className={styles.tableContainer}>
|
||||
<div className={styles.tableActions}>
|
||||
<Typography color="var(--grayscale-2)" variant="h3">
|
||||
EMI Bucket wise Summary
|
||||
</Typography>
|
||||
<Button
|
||||
startAdornment={<Download />}
|
||||
className={styles.downloadReport}
|
||||
variant="text"
|
||||
onClick={handleDownloadReport}
|
||||
disabled={tableData.length === 0}
|
||||
>
|
||||
Download Report
|
||||
</Button>
|
||||
</div>
|
||||
<div className={styles.dataContainer}>
|
||||
<div className={styles.tableContainer}>
|
||||
<AgTable
|
||||
ref={ref}
|
||||
columnDefs={columnData}
|
||||
style={{
|
||||
height: 899.5
|
||||
}}
|
||||
headerHeight={70}
|
||||
defaultColDef={{
|
||||
suppressMovable: true,
|
||||
wrapText: true,
|
||||
autoHeight: true
|
||||
}}
|
||||
theme={'alpine'}
|
||||
rowData={data}
|
||||
onSortChanged={handleSort}
|
||||
pagination
|
||||
suppressPaginationPanel={true}
|
||||
paginationWrapperClasses="paginationWrapperClasses"
|
||||
animateRows
|
||||
sizeColumnsToFit
|
||||
suppressRowClickSelection={true}
|
||||
suppressRowDrag={false}
|
||||
alternateRowColor="var(--greyscale-content-4)"
|
||||
getRowHeight={params => params.data?.rowHeight}
|
||||
/>
|
||||
{!data.length ? <NoDataFound className={styles.noDataFound} /> : null}
|
||||
</div>
|
||||
<div className={styles.fb32}>
|
||||
<NumberOfCases
|
||||
dataTObeFed={data.find(i => i.key === 'totalCases')}
|
||||
casesData={data.find(i => i.key === 'totalCases')}
|
||||
/>
|
||||
<CallsOverView
|
||||
data={dataObject}
|
||||
updateAndNavigate={updateAndNavigate}
|
||||
params={params}
|
||||
/>
|
||||
<PTPOverView data={dataObject} updateAndNavigate={updateAndNavigate} params={params} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Loader show={loading} className={'loadingState'} animate={false} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Index;
|
||||
@@ -4,7 +4,6 @@
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
border-radius: 0px 0px 32px 32px;
|
||||
box-shadow: 0px 14px 38px 0px rgba(125, 125, 125, 0.08);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { SelectPickerOptionProps } from '@cp/src/components/interfaces';
|
||||
import { IAllDataBucketWiseSummary } from '../types';
|
||||
|
||||
export enum ViewType {
|
||||
TEAM_LEAD = 'TEAM_LEAD',
|
||||
SENIOR_TEAM_LEAD = 'SENIOR_TEAM_LEAD'
|
||||
@@ -12,5 +15,500 @@ export const TABLE_DEFAULT_VALUES = {
|
||||
page: '1',
|
||||
orderBy: 'name',
|
||||
order: 'asc',
|
||||
goToStart: 0
|
||||
goToStart: 0,
|
||||
depositionSummaryPTPOverViewFilter: '<4k',
|
||||
depositionSummaryCallOverViewFilter: '<4k'
|
||||
};
|
||||
|
||||
export enum summaryGroup {
|
||||
'<4k' = 'Less than 4k',
|
||||
'4k-7k' = '4k to 7k',
|
||||
'10k+' = 'More than 10k',
|
||||
'7k-10k' = '7k to 10k'
|
||||
}
|
||||
|
||||
export enum summaryGroupColorMapping {
|
||||
'<4k' = '#FFAD1E',
|
||||
'4k-7k' = '#FA896B',
|
||||
'10k+' = '#5D87FF',
|
||||
'7k-10k' = '#6FE8C8'
|
||||
}
|
||||
|
||||
export enum emiBucketWiseRowsEnum {
|
||||
EMI_ALLOCATED = 'EMI_ALLOCATED',
|
||||
EMI_CE = 'EMI_CE',
|
||||
TOTAL_CASES = 'TOTAL_CASES',
|
||||
UNPAID_CASES = 'UNPAID_CASES',
|
||||
TOTAL_CALLS = 'TOTAL_CALLS',
|
||||
VIA_LONGHORN = 'VIA_LONGHORN',
|
||||
VIA_AMEYO = 'VIA_AMEYO',
|
||||
VIA_SELF = 'VIA_SELF',
|
||||
COVERAGE_UNPAID_CASES = 'COVERAGE_UNPAID_CASES',
|
||||
AVG_CALLS_UNPAID_CASES = 'AVG_CALLS_UNPAID_CASES',
|
||||
AVG_UNIQUE_DAYS_CALLED_UNPAID_CASES = 'AVG_UNIQUE_DAYS_CALLED_UNPAID_CASES',
|
||||
PTP_GENERATED = 'PTP_GENERATED',
|
||||
PTP_CONVERTED = 'PTP_CONVERTED',
|
||||
BROKEN_PTP = 'BROKEN_PTP',
|
||||
FUTURE_PTP = 'FUTURE_PTP'
|
||||
}
|
||||
|
||||
export enum emiBucketWiseRowsReadableNameEnum {
|
||||
EMI_ALLOCATED = 'EMI ALLOCATED',
|
||||
EMI_CE = 'EMI CE',
|
||||
TOTAL_CASES = 'TOTAL CASES',
|
||||
UNPAID_CASES = 'UNPAID CASES',
|
||||
TOTAL_CALLS = 'TOTAL CALLS',
|
||||
VIA_LONGHORN = 'VIA LONGHORN',
|
||||
VIA_AMEYO = 'VIA AMEYO',
|
||||
VIA_SELF = 'VIA SELF',
|
||||
COVERAGE_UNPAID_CASES = 'COVERAGE UNPAID CASES',
|
||||
AVG_CALLS_UNPAID_CASES = 'AVG CALLS UNPAID CASES',
|
||||
AVG_UNIQUE_DAYS_CALLED_UNPAID_CASES = 'AVG UNIQUE DAYS CALLED UNPAID CASES',
|
||||
PTP_GENERATED = 'PTP GENERATED',
|
||||
PTP_CONVERTED = 'PTP CONVERTED',
|
||||
BROKEN_PTP = 'BROKEN PTP',
|
||||
FUTURE_PTP = 'FUTURE PTP'
|
||||
}
|
||||
|
||||
export const emiBucketWiseData = [
|
||||
{
|
||||
name: emiBucketWiseRowsEnum.EMI_ALLOCATED,
|
||||
lessThan4k: 0,
|
||||
between4k7k: 0,
|
||||
between7k10k: 0,
|
||||
greaterThan10k: 0,
|
||||
key: 'emiAllocated'
|
||||
},
|
||||
{
|
||||
name: emiBucketWiseRowsEnum.EMI_CE,
|
||||
lessThan4k: 0,
|
||||
between4k7k: 0,
|
||||
between7k10k: 0,
|
||||
greaterThan10k: 0,
|
||||
key: 'emiCollectionEfficiency'
|
||||
},
|
||||
{
|
||||
name: emiBucketWiseRowsEnum.UNPAID_CASES,
|
||||
lessThan4k: 0,
|
||||
between4k7k: 0,
|
||||
between7k10k: 0,
|
||||
greaterThan10k: 0,
|
||||
key: 'unpaidCases'
|
||||
},
|
||||
{
|
||||
name: emiBucketWiseRowsEnum.TOTAL_CALLS,
|
||||
lessThan4k: 0,
|
||||
between4k7k: 0,
|
||||
between7k10k: 0,
|
||||
greaterThan10k: 0,
|
||||
key: 'totalCalls'
|
||||
},
|
||||
{
|
||||
name: emiBucketWiseRowsEnum.VIA_LONGHORN,
|
||||
lessThan4k: 0,
|
||||
between4k7k: 0,
|
||||
between7k10k: 0,
|
||||
greaterThan10k: 0,
|
||||
key: 'slashCalls'
|
||||
},
|
||||
{
|
||||
name: emiBucketWiseRowsEnum.VIA_AMEYO,
|
||||
lessThan4k: 0,
|
||||
between4k7k: 0,
|
||||
between7k10k: 0,
|
||||
greaterThan10k: 0,
|
||||
key: 'ameyoCalls'
|
||||
},
|
||||
{
|
||||
name: emiBucketWiseRowsEnum.VIA_SELF,
|
||||
lessThan4k: 0,
|
||||
between4k7k: 0,
|
||||
between7k10k: 0,
|
||||
greaterThan10k: 0,
|
||||
selfCalls: 'selfCalls'
|
||||
},
|
||||
{
|
||||
name: emiBucketWiseRowsEnum.COVERAGE_UNPAID_CASES,
|
||||
lessThan4k: 0,
|
||||
between4k7k: 0,
|
||||
between7k10k: 0,
|
||||
greaterThan10k: 0,
|
||||
key: 'unpaidCasesCoverage'
|
||||
},
|
||||
{
|
||||
name: emiBucketWiseRowsEnum.AVG_CALLS_UNPAID_CASES,
|
||||
lessThan4k: 0,
|
||||
between4k7k: 0,
|
||||
between7k10k: 0,
|
||||
greaterThan10k: 0,
|
||||
key: 'averageCallsPerUnpaidCases'
|
||||
},
|
||||
{
|
||||
name: emiBucketWiseRowsEnum.AVG_UNIQUE_DAYS_CALLED_UNPAID_CASES,
|
||||
lessThan4k: 0,
|
||||
between4k7k: 0,
|
||||
between7k10k: 0,
|
||||
greaterThan10k: 0,
|
||||
key: 'averageUniqueDaysCalledPerUnpaidCases'
|
||||
},
|
||||
{
|
||||
name: emiBucketWiseRowsEnum.PTP_GENERATED,
|
||||
lessThan4k: 0,
|
||||
between4k7k: 0,
|
||||
between7k10k: 0,
|
||||
greaterThan10k: 0,
|
||||
key: 'generatedPtpCount'
|
||||
},
|
||||
{
|
||||
name: emiBucketWiseRowsEnum.PTP_CONVERTED,
|
||||
lessThan4k: 0,
|
||||
between4k7k: 0,
|
||||
between7k10k: 0,
|
||||
greaterThan10k: 0,
|
||||
key: 'convertedPtpCount'
|
||||
},
|
||||
{
|
||||
name: emiBucketWiseRowsEnum.BROKEN_PTP,
|
||||
lessThan4k: 0,
|
||||
between4k7k: 0,
|
||||
between7k10k: 0,
|
||||
greaterThan10k: 0,
|
||||
key: 'brokenPtpCount'
|
||||
}
|
||||
];
|
||||
export const emiBucketWiseRows = [
|
||||
'EMI Allocated',
|
||||
'EMI CE %',
|
||||
'% Unpaid cases',
|
||||
'Total Calls',
|
||||
'Via Longhorn',
|
||||
'Via Ameyo',
|
||||
'Via Self',
|
||||
'Coverage % Unpaid cases',
|
||||
'Avg calls/Unpaid cases',
|
||||
'Avg Unique Days Called/Unpaid cases',
|
||||
'% PTP Generated',
|
||||
'% PTP Converted',
|
||||
'% Broken PTP'
|
||||
];
|
||||
// create emiBucketWiseData object with keys as enum values
|
||||
export type IEmiBucketWiseDataObject = typeof emiBucketWiseDataObject;
|
||||
|
||||
export const emiBucketWiseDataObject = {
|
||||
[emiBucketWiseRowsEnum.EMI_ALLOCATED]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'emiAllocated',
|
||||
name: 'EMI Allocated'
|
||||
},
|
||||
[emiBucketWiseRowsEnum.EMI_CE]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'emiCollectionEfficiency',
|
||||
name: 'EMI CE %'
|
||||
},
|
||||
[emiBucketWiseRowsEnum.TOTAL_CASES]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'totalCases',
|
||||
name: 'Total Cases',
|
||||
bold: true
|
||||
},
|
||||
[emiBucketWiseRowsEnum.UNPAID_CASES]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'unpaidCases',
|
||||
name: 'Unpaid Cases'
|
||||
},
|
||||
[emiBucketWiseRowsEnum.TOTAL_CALLS]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'totalCalls',
|
||||
name: 'Total Calls',
|
||||
bold: true
|
||||
},
|
||||
[emiBucketWiseRowsEnum.VIA_LONGHORN]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'slashCalls',
|
||||
name: 'Via Longhorn',
|
||||
subPoint: true,
|
||||
blue: true
|
||||
},
|
||||
[emiBucketWiseRowsEnum.VIA_AMEYO]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'ameyoCalls',
|
||||
name: 'Via Ameyo',
|
||||
subPoint: true,
|
||||
blue: true
|
||||
},
|
||||
[emiBucketWiseRowsEnum.VIA_SELF]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'selfCalls',
|
||||
name: 'Via Self',
|
||||
subPoint: true,
|
||||
blue: true
|
||||
},
|
||||
[emiBucketWiseRowsEnum.COVERAGE_UNPAID_CASES]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'unpaidCasesCoverage',
|
||||
name: 'Coverage on Unpaid Cases %'
|
||||
},
|
||||
[emiBucketWiseRowsEnum.AVG_CALLS_UNPAID_CASES]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'averageCallsPerUnpaidCases',
|
||||
name: 'Avg Calls/Unpaid Cases'
|
||||
},
|
||||
[emiBucketWiseRowsEnum.AVG_UNIQUE_DAYS_CALLED_UNPAID_CASES]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'averageUniqueDaysCalledPerUnpaidCases',
|
||||
name: 'Avg Unique Days Called/Unpaid Cases'
|
||||
},
|
||||
[emiBucketWiseRowsEnum.PTP_GENERATED]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'generatedPtpCount',
|
||||
name: 'PTP Generated',
|
||||
bold: true
|
||||
},
|
||||
[emiBucketWiseRowsEnum.PTP_CONVERTED]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'convertedPtpCount',
|
||||
name: 'PTP Converted',
|
||||
subPoint: true
|
||||
},
|
||||
[emiBucketWiseRowsEnum.BROKEN_PTP]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'brokenPtpCount',
|
||||
name: 'Broken PTP',
|
||||
subPoint: true
|
||||
},
|
||||
[emiBucketWiseRowsEnum.FUTURE_PTP]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'futurePtpCount',
|
||||
name: 'Future PTP',
|
||||
subPoint: true
|
||||
}
|
||||
};
|
||||
export const getRowObject = () => {
|
||||
return {
|
||||
[emiBucketWiseRowsEnum.EMI_ALLOCATED]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'emiAllocated',
|
||||
name: 'EMI Allocated',
|
||||
isCurrency: true
|
||||
},
|
||||
[emiBucketWiseRowsEnum.EMI_CE]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'emiCollectionEfficiency',
|
||||
name: 'EMI CE %',
|
||||
percentage: true
|
||||
},
|
||||
[emiBucketWiseRowsEnum.TOTAL_CASES]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'totalCases',
|
||||
name: 'Total Cases',
|
||||
bold: true
|
||||
},
|
||||
[emiBucketWiseRowsEnum.UNPAID_CASES]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'unpaidCases',
|
||||
name: 'Unpaid Cases'
|
||||
},
|
||||
[emiBucketWiseRowsEnum.TOTAL_CALLS]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'totalCalls',
|
||||
name: 'Total Calls',
|
||||
bold: true
|
||||
},
|
||||
[emiBucketWiseRowsEnum.VIA_LONGHORN]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'slashCalls',
|
||||
name: 'Via Longhorn',
|
||||
subPoint: true,
|
||||
blue: true,
|
||||
rowHeight: 42
|
||||
},
|
||||
[emiBucketWiseRowsEnum.VIA_AMEYO]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'ameyoCalls',
|
||||
name: 'Via Ameyo',
|
||||
subPoint: true,
|
||||
blue: true,
|
||||
rowHeight: 42
|
||||
},
|
||||
[emiBucketWiseRowsEnum.VIA_SELF]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'selfCalls',
|
||||
name: 'Via Self',
|
||||
subPoint: true,
|
||||
blue: true,
|
||||
rowHeight: 42
|
||||
},
|
||||
[emiBucketWiseRowsEnum.COVERAGE_UNPAID_CASES]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'unpaidCasesCoverage',
|
||||
name: 'Coverage on Unpaid Cases %',
|
||||
blueBackground: true,
|
||||
percentage: true
|
||||
},
|
||||
[emiBucketWiseRowsEnum.AVG_CALLS_UNPAID_CASES]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'averageCallsPerUnpaidCases',
|
||||
name: 'Avg Calls/Unpaid Cases'
|
||||
},
|
||||
[emiBucketWiseRowsEnum.AVG_UNIQUE_DAYS_CALLED_UNPAID_CASES]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'averageUniqueDaysCalledPerUnpaidCases',
|
||||
name: 'Avg Unique Days Called/Unpaid Cases'
|
||||
},
|
||||
[emiBucketWiseRowsEnum.PTP_GENERATED]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'generatedPtpCount',
|
||||
name: 'PTP Generated',
|
||||
bold: true
|
||||
},
|
||||
[emiBucketWiseRowsEnum.PTP_CONVERTED]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'convertedPtpCount',
|
||||
name: 'PTP Converted',
|
||||
subPoint: true,
|
||||
blue: true,
|
||||
rowHeight: 42
|
||||
},
|
||||
[emiBucketWiseRowsEnum.BROKEN_PTP]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'brokenPtpCount',
|
||||
name: 'Broken PTP',
|
||||
subPoint: true,
|
||||
blue: true,
|
||||
rowHeight: 42
|
||||
},
|
||||
[emiBucketWiseRowsEnum.FUTURE_PTP]: {
|
||||
'<4k': 0,
|
||||
'4k-7k': 0,
|
||||
'7k-10k': 0,
|
||||
'10k+': 0,
|
||||
key: 'futurePtpCount',
|
||||
name: 'Future PTP',
|
||||
subPoint: true,
|
||||
blue: true,
|
||||
rowHeight: 42
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const DROPDOWN_OPTIONS = [
|
||||
{ value: '<4k', label: 'Less than 4k' },
|
||||
{ value: '4k-7k', label: '4k to 7k' },
|
||||
{ value: '7k-10k', label: '7k to 10k' },
|
||||
{ value: '10k+', label: 'More than 10k' }
|
||||
] as SelectPickerOptionProps[];
|
||||
|
||||
export const SUMMARY_GROUP = ['<4k', '4k-7k', '10k+', '7k-10k'];
|
||||
|
||||
export const generateFinalSummaryGroup = () => {
|
||||
const finalSummaryGroup: IAllDataBucketWiseSummary = {};
|
||||
for (const key of SUMMARY_GROUP) {
|
||||
finalSummaryGroup[key as string] = {
|
||||
emiAllocated: 0,
|
||||
emiCollectionEfficiency: 0,
|
||||
totalCases: 0,
|
||||
unpaidCases: 0,
|
||||
totalCalls: 0,
|
||||
slashCalls: 0,
|
||||
ameyoCalls: 0,
|
||||
selfCalls: 0,
|
||||
unpaidCasesCoverage: 0,
|
||||
averageCallsPerUnpaidCases: 0,
|
||||
averageUniqueDaysCalledPerUnpaidCases: 0,
|
||||
generatedPtpCount: 0,
|
||||
convertedPtpCount: 0,
|
||||
brokenPtpCount: 0,
|
||||
futurePtpCount: 0,
|
||||
emiCollected: 0,
|
||||
unpaidCasesCovered: 0
|
||||
};
|
||||
}
|
||||
return finalSummaryGroup;
|
||||
};
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import Filter from './components/filters';
|
||||
import AgentPerformance from './components/agentPerformance';
|
||||
import { getAgentInputData, getAgentPerformanceData, getDespositionSummary } from './action';
|
||||
import {
|
||||
getAgentInputData,
|
||||
getAgentPerformanceData,
|
||||
getDespositionSummary,
|
||||
getEMIBucketWiseSummary
|
||||
} from './action';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { createQueryParams, readQueryParams } from '@cp/src/utils/QueryParamsHelper';
|
||||
import { IAgent, IAgentPerformance, IAgentPerformanceParams, IDepositionSummary } from './types';
|
||||
import {
|
||||
IAgent,
|
||||
IAgentPerformance,
|
||||
IAgentPerformanceParams,
|
||||
IDepositionSummary,
|
||||
IEMIBucketWiseSummary
|
||||
} from './types';
|
||||
import { AGENT_PERFORMANCE_TABLE, TABLE_DEFAULT_VALUES, pollingInterval } from './constants';
|
||||
import { useLocation, useNavigate } from 'react-router';
|
||||
import AgentInput from './components/agentInput';
|
||||
@@ -13,6 +24,7 @@ import store, { RootState } from '@cp/src/store';
|
||||
import {
|
||||
setAgentPerformanceFiltered,
|
||||
setDespositionSummaryFilter,
|
||||
setEmiBucketWiseSummaryFilter,
|
||||
setFilteredData
|
||||
} from './reducer';
|
||||
import { poll } from '@cp/src/utils/polling';
|
||||
@@ -25,16 +37,22 @@ import { Typography } from '@navi/web-ui/lib/primitives';
|
||||
import AgentInputIcon from '@cp/src/assets/icons/AgentInputIcon';
|
||||
import { addClickstreamEvent } from '@cp/src/service/clickStreamEventService';
|
||||
import { CLICKSTREAM_EVENT_NAMES } from '@cp/src/service/clickStream.constant';
|
||||
|
||||
import EmiBucketSummary from './components/emiBucketWiseSummary';
|
||||
const Index = () => {
|
||||
const dispatch = useDispatch();
|
||||
const { loading, loadingAgentPerformance, agentData, IAgentPerformance, despositionSummary } =
|
||||
useSelector((state: RootState) => state.teleSensei);
|
||||
const {
|
||||
loading,
|
||||
loadingAgentPerformance,
|
||||
agentData,
|
||||
IAgentPerformance,
|
||||
despositionSummary,
|
||||
emiBucketWiseSummary
|
||||
} = useSelector((state: RootState) => state.teleSensei);
|
||||
const location = useLocation();
|
||||
|
||||
const { [AGENT_PERFORMANCE_TABLE]: params } = readQueryParams();
|
||||
const navigate = useNavigate();
|
||||
const unsubscribeRef = React.useRef<() => void>();
|
||||
|
||||
const updateAndNavigate = (updatedParams: IAgentPerformanceParams) => {
|
||||
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.LH_TELE_SENSEI_FILTER_APPLY, { updatedParams });
|
||||
const url = createQueryParams({
|
||||
@@ -47,6 +65,7 @@ const Index = () => {
|
||||
dispatch(getAgentInputData());
|
||||
dispatch(getAgentPerformanceData());
|
||||
dispatch(getDespositionSummary());
|
||||
dispatch(getEMIBucketWiseSummary());
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -65,10 +84,18 @@ const Index = () => {
|
||||
queryParams['pageSizeInput'] = TABLE_DEFAULT_VALUES.rowsPerPage;
|
||||
}
|
||||
if (!queryParams?.pageNoDisposition) {
|
||||
queryParams['pageNoDisposition'] = '1';
|
||||
queryParams['pageNoDisposition'] = TABLE_DEFAULT_VALUES.page;
|
||||
}
|
||||
if (!queryParams?.pageSizeDisposition) {
|
||||
queryParams['pageSizeDisposition'] = '10';
|
||||
queryParams['pageSizeDisposition'] = TABLE_DEFAULT_VALUES.rowsPerPage;
|
||||
}
|
||||
if (!queryParams?.depositionSummaryCallOverViewFilter) {
|
||||
queryParams['depositionSummaryCallOverViewFilter'] =
|
||||
TABLE_DEFAULT_VALUES.depositionSummaryCallOverViewFilter;
|
||||
}
|
||||
if (!queryParams?.depositionSummaryPTPOverViewFilter) {
|
||||
queryParams['depositionSummaryPTPOverViewFilter'] =
|
||||
TABLE_DEFAULT_VALUES.depositionSummaryPTPOverViewFilter;
|
||||
}
|
||||
updateAndNavigate(queryParams);
|
||||
}, []);
|
||||
@@ -79,6 +106,7 @@ const Index = () => {
|
||||
let filteredAgentData: IAgent[] = [];
|
||||
let filteredAgentInput: IAgentPerformance[] = [];
|
||||
let filteredDespositionData: IDepositionSummary[] = [];
|
||||
let filteredEmiBucketData: IEMIBucketWiseSummary[] = [];
|
||||
// filtering this out if both the filter selected
|
||||
if (params?.teamLeadId && params?.agentId) {
|
||||
const dataAfterTLFilter = agentData?.filter(
|
||||
@@ -107,6 +135,15 @@ const Index = () => {
|
||||
);
|
||||
dispatch(setDespositionSummaryFilter(filteredDespositionData));
|
||||
|
||||
const dataAfterTLFilterEmiBucket = emiBucketWiseSummary?.filter(
|
||||
agentData => agentData?.tlReferenceId === params?.teamLeadId
|
||||
);
|
||||
|
||||
filteredEmiBucketData = dataAfterTLFilterEmiBucket?.filter(agentData =>
|
||||
selectedAgents?.some((agentID: string) => agentData?.agentReferenceId === agentID)
|
||||
);
|
||||
dispatch(setEmiBucketWiseSummaryFilter(filteredEmiBucketData));
|
||||
|
||||
return;
|
||||
}
|
||||
if (params?.teamLeadId && !params?.agentId) {
|
||||
@@ -124,6 +161,11 @@ const Index = () => {
|
||||
agentData => agentData?.tlReferenceId === params?.teamLeadId
|
||||
);
|
||||
dispatch(setDespositionSummaryFilter(filteredDespositionData));
|
||||
|
||||
filteredEmiBucketData = emiBucketWiseSummary?.filter(
|
||||
agentData => agentData?.tlReferenceId === params?.teamLeadId
|
||||
);
|
||||
dispatch(setEmiBucketWiseSummaryFilter(filteredEmiBucketData));
|
||||
return;
|
||||
}
|
||||
if (!params?.teamLeadId && params?.agentId) {
|
||||
@@ -142,6 +184,11 @@ const Index = () => {
|
||||
selectedAgents?.some((agentID: string) => agentData?.agentReferenceId === agentID)
|
||||
);
|
||||
dispatch(setDespositionSummaryFilter(filteredDespositionData));
|
||||
|
||||
filteredEmiBucketData = emiBucketWiseSummary?.filter(agentData =>
|
||||
selectedAgents?.some((agentID: string) => agentData?.agentReferenceId === agentID)
|
||||
);
|
||||
dispatch(setEmiBucketWiseSummaryFilter(filteredEmiBucketData));
|
||||
return;
|
||||
}
|
||||
if (!params?.teamLeadId && !params?.agentId) {
|
||||
@@ -153,9 +200,12 @@ const Index = () => {
|
||||
|
||||
filteredDespositionData = despositionSummary;
|
||||
dispatch(setDespositionSummaryFilter(filteredDespositionData));
|
||||
|
||||
filteredEmiBucketData = emiBucketWiseSummary;
|
||||
dispatch(setEmiBucketWiseSummaryFilter(filteredEmiBucketData));
|
||||
return;
|
||||
}
|
||||
}, [location, agentData, IAgentPerformance, despositionSummary]);
|
||||
}, [location, agentData, IAgentPerformance, despositionSummary, emiBucketWiseSummary]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -175,6 +225,11 @@ const Index = () => {
|
||||
updateAndNavigate={updateAndNavigate}
|
||||
url={location.hash}
|
||||
/>
|
||||
<EmiBucketSummary
|
||||
params={params}
|
||||
updateAndNavigate={updateAndNavigate}
|
||||
url={location.hash}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Loader show={loading || loadingAgentPerformance} />
|
||||
|
||||
@@ -17,7 +17,10 @@ const initialState: IAgentData = {
|
||||
lastRefreshedTimeStampInput: '',
|
||||
despositionSummary: [],
|
||||
loadingDespositionSummary: false,
|
||||
despositionSummaryFilter: []
|
||||
despositionSummaryFilter: [],
|
||||
emiBucketWiseSummary: [],
|
||||
loadingEmiBucketWiseSummary: false,
|
||||
emiBucketWiseSummaryFilter: []
|
||||
};
|
||||
|
||||
const TeleSenseiSlice = createSlice({
|
||||
@@ -58,6 +61,15 @@ const TeleSenseiSlice = createSlice({
|
||||
setDespositionSummary(state, action) {
|
||||
const { data } = action.payload;
|
||||
state.despositionSummary = data;
|
||||
},
|
||||
setEmiBucketWiseSummary(state, action) {
|
||||
state.emiBucketWiseSummary = action.payload;
|
||||
},
|
||||
setLoadingEmiBucketWiseSummary(state, action) {
|
||||
state.loadingEmiBucketWiseSummary = action.payload;
|
||||
},
|
||||
setEmiBucketWiseSummaryFilter(state, action) {
|
||||
state.emiBucketWiseSummaryFilter = action.payload;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -71,7 +83,10 @@ export const {
|
||||
setAgentPerformanceFiltered,
|
||||
setDespositionSummaryFilter,
|
||||
setLoadingDespositionSummary,
|
||||
setDespositionSummary
|
||||
setDespositionSummary,
|
||||
setEmiBucketWiseSummary,
|
||||
setEmiBucketWiseSummaryFilter,
|
||||
setLoadingEmiBucketWiseSummary
|
||||
} = TeleSenseiSlice.actions;
|
||||
|
||||
export default TeleSenseiSlice.reducer;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ViewType } from '../constants';
|
||||
import { A } from 'msw/lib/core/RequestHandler-bb5cbb8f';
|
||||
import { IEmiBucketWiseDataObject, ViewType } from '../constants';
|
||||
|
||||
export type IViewType = keyof typeof ViewType | null;
|
||||
|
||||
@@ -18,6 +19,10 @@ export interface IAgentPerformanceParams {
|
||||
sortOrderDisposition?: string;
|
||||
pageNoDisposition?: string;
|
||||
pageSizeDisposition?: string;
|
||||
depositionSummaryCallOverViewFilter?: string;
|
||||
depositionSummaryPTPOverViewFilter?: string;
|
||||
unpaidCasesCovered?: number;
|
||||
unpaidCases?: number;
|
||||
}
|
||||
|
||||
export interface IFilters {
|
||||
@@ -68,6 +73,9 @@ export interface IAgentData {
|
||||
despositionSummary: IDepositionSummary[];
|
||||
loadingDespositionSummary: boolean;
|
||||
despositionSummaryFilter: IDepositionSummary[];
|
||||
emiBucketWiseSummary: IEMIBucketWiseSummary[];
|
||||
loadingEmiBucketWiseSummary: boolean;
|
||||
emiBucketWiseSummaryFilter: IEMIBucketWiseSummary[];
|
||||
}
|
||||
|
||||
export enum FilterType {
|
||||
@@ -115,3 +123,79 @@ export interface IDepositionSummary {
|
||||
ptpTodayCount: number;
|
||||
ptpTodayEmi: number;
|
||||
}
|
||||
|
||||
export interface IEMIBucketWiseSummary {
|
||||
agentName: string;
|
||||
agentReferenceId: string;
|
||||
tlReferenceId: string;
|
||||
dueCycle: string;
|
||||
bucketWiseSummary: IBucketWiseSummary[];
|
||||
}
|
||||
|
||||
interface IBucketWiseSummary {
|
||||
bucketGroup: string;
|
||||
emiAllocated: number;
|
||||
emiCollectionEfficiency: number;
|
||||
totalCases: number;
|
||||
unpaidCases: number;
|
||||
totalCalls: number;
|
||||
slashCalls: number;
|
||||
ameyoCalls: number;
|
||||
selfCalls: number;
|
||||
unpaidCasesCoverage: number;
|
||||
averageCallsPerUnpaidCases: number;
|
||||
averageUniqueDaysCalledPerUnpaidCases: number;
|
||||
generatedPtpCount: number;
|
||||
convertedPtpCount: number;
|
||||
brokenPtpCount: number;
|
||||
futurePtpCount: number;
|
||||
emiCollected: number;
|
||||
}
|
||||
|
||||
export interface IAllDataBucketWiseSummary {
|
||||
[key: string]: IBuckerrWiseSummarySum;
|
||||
}
|
||||
|
||||
export interface IBuckerrWiseSummarySum {
|
||||
emiAllocated: number;
|
||||
emiCollectionEfficiency: number;
|
||||
totalCases: number;
|
||||
unpaidCases: number;
|
||||
totalCalls: number;
|
||||
slashCalls: number;
|
||||
ameyoCalls: number;
|
||||
selfCalls: number;
|
||||
unpaidCasesCoverage: number;
|
||||
averageCallsPerUnpaidCases: number;
|
||||
averageUniqueDaysCalledPerUnpaidCases: number;
|
||||
generatedPtpCount: number;
|
||||
convertedPtpCount: number;
|
||||
brokenPtpCount: number;
|
||||
futurePtpCount: number;
|
||||
emiCollected: number;
|
||||
unpaidCasesCovered: number;
|
||||
}
|
||||
|
||||
export interface ICallsOverView {
|
||||
data: IEmiBucketWiseDataObject;
|
||||
params: IAgentPerformanceParams;
|
||||
updateAndNavigate: (params: IAgentPerformanceParams) => void;
|
||||
}
|
||||
|
||||
export interface CashEarnedChartHCProps {
|
||||
dataTObeFed: Array<responseDataType>;
|
||||
casesData: Array<responseDataType>;
|
||||
}
|
||||
|
||||
export type responseDataType = {
|
||||
label: string;
|
||||
value: string;
|
||||
fill: string;
|
||||
color: string;
|
||||
};
|
||||
|
||||
export interface IPTPOverView {
|
||||
data: IEmiBucketWiseDataObject;
|
||||
params: IAgentPerformanceParams;
|
||||
updateAndNavigate: (params: IAgentPerformanceParams) => void;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,8 @@ export enum Roles {
|
||||
NAVI_INHOUSE_FIELD_ZONAL_MANAGER = 'NAVI_INHOUSE_FIELD_ZONAL_MANAGER',
|
||||
ROLE_NAVI_FIELD_AGENCY_TEAM_LEAD = 'ROLE_NAVI_FIELD_AGENCY_TEAM_LEAD',
|
||||
ROLE_HUMAN_REMINDER_TEAM_LEAD = 'ROLE_HUMAN_REMINDER_TEAM_LEAD',
|
||||
ROLE_HUMAN_REMINDER_CHAT_AGENT = 'ROLE_HUMAN_REMINDER_CHAT_AGENT'
|
||||
ROLE_HUMAN_REMINDER_CHAT_AGENT = 'ROLE_HUMAN_REMINDER_CHAT_AGENT',
|
||||
ROLE_NAVI_TELE_INHOUSE_TEAM_LEAD = 'ROLE_NAVI_TELE_INHOUSE_TEAM_LEAD'
|
||||
}
|
||||
|
||||
export const permissionScreenConstants = {
|
||||
|
||||
@@ -167,7 +167,8 @@ export enum ApiKeys {
|
||||
GET_AGENCY_NAME_OPTIONS,
|
||||
GET_AGENCY_DETAILS_DATA,
|
||||
GET_AGENT_PERFORMANCE_DATA,
|
||||
GET_AGENT_PERFORMANCE_TL_DATA
|
||||
GET_AGENT_PERFORMANCE_TL_DATA,
|
||||
EMI_BUCKET_WISE_SUMMARY
|
||||
}
|
||||
|
||||
// TODO: try to get rid of `as`
|
||||
@@ -325,6 +326,8 @@ API_URLS[ApiKeys.GET_AGENT_PERFORMANCE_DATA] =
|
||||
'/longhorn/external-agency-performance-dashboard/field-governance/agent';
|
||||
API_URLS[ApiKeys.GET_AGENT_PERFORMANCE_TL_DATA] =
|
||||
'/longhorn/external-agency-performance-dashboard/overall-performance/agent-performance';
|
||||
API_URLS[ApiKeys.EMI_BUCKET_WISE_SUMMARY] =
|
||||
'/team-lead/dashboard/reportees-emi-bucket-wise-summary';
|
||||
|
||||
// TODO: try to get rid of `as`
|
||||
const MOCK_API_URLS: Record<ApiKeys, string> = {} as Record<ApiKeys, string>;
|
||||
|
||||
Reference in New Issue
Block a user