TP-111|Kunal|HRC EMI CARD revamp (#1003)
* TP-111|Kunal|HRC EMI CARD revamp * TP-111|Kunal|HRC EMI CARD revamp * TP-111|Kunal|HRC EMI CARD revamp * TP-111|Kunal|HRC EMI CARD revamp * TP-111|Kunal|HRC EMI CARD revamp * TP-111|Kunal|HRC EMI CARD revamp * TP-111|Kunal|HRC EMI CARD revamp * TP-111|Kunal|HRC EMI CARD revamp * TP-111|Kunal|HRC EMI CARD revamp * TP-111|Kunal|HRC EMI CARD revamp * TP-111|Kunal|HRC EMI CARD revamp * TP-111|Kunal|HRC EMI CARD revamp
This commit is contained in:
45
src/assets/icons/HourglassIconV2.tsx
Normal file
45
src/assets/icons/HourglassIconV2.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import * as React from 'react';
|
||||
|
||||
const HourglassIconV2 = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width={14} height={14} viewBox="0 0 14 14" fill="none">
|
||||
<path
|
||||
d="M2.918 1.483h8.164M2.918 12.529h8.164"
|
||||
stroke="#0276FE"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path d="m7 9.163 1.44 1.44h1.681v-.48a3.12 3.12 0 1 0-6.243 0v.48H5.56z" fill="#fff" />
|
||||
<path d="M8.44 10.604 7 9.164l-1.441 1.44h-1.68v1.92h6.242v-1.92z" fill="#0276FE" />
|
||||
<path
|
||||
d="M8.44 10.604 7 9.164l-1.441 1.44h-1.68v1.92h6.242v-1.92z"
|
||||
stroke="#0276FE"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M10.121 3.884V1.483H3.878v2.4c0 .697.234 1.374.664 1.921h4.914a3.1 3.1 0 0 0 .665-1.92"
|
||||
fill="#fff"
|
||||
/>
|
||||
<path
|
||||
d="M10.121 3.884V1.483H3.878v2.4c0 .697.234 1.374.664 1.921h4.914a3.1 3.1 0 0 0 .665-1.92"
|
||||
stroke="#0276FE"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path d="M4.542 5.805a3.115 3.115 0 0 0 4.915 0z" fill="#fff" />
|
||||
<path
|
||||
d="M4.542 5.805a3.115 3.115 0 0 0 4.915 0z"
|
||||
fill="#0276FE"
|
||||
stroke="#0276FE"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="m7 9.163 1.44 1.44h1.681v-.48a3.12 3.12 0 1 0-6.243 0v.48H5.56z"
|
||||
stroke="#0276FE"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export default HourglassIconV2;
|
||||
@@ -12,7 +12,8 @@ import {
|
||||
useMergeRefs,
|
||||
FloatingPortal,
|
||||
FloatingArrow,
|
||||
hide
|
||||
hide,
|
||||
useTransitionStyles
|
||||
} from '@floating-ui/react';
|
||||
import type { Placement } from '@floating-ui/react';
|
||||
import { arrow } from '@floating-ui/dom';
|
||||
@@ -31,6 +32,8 @@ interface PopperOptions {
|
||||
openOnClick?: boolean;
|
||||
mainAxisOffset?: number;
|
||||
crossAxisOffset?: number;
|
||||
disableCloseOnOutsideClick?: boolean;
|
||||
transform?: boolean;
|
||||
}
|
||||
|
||||
interface PopperContentProps {
|
||||
@@ -62,7 +65,9 @@ export function usePopper({
|
||||
hiddenPadding = 16,
|
||||
openOnClick = true,
|
||||
mainAxisOffset = 9,
|
||||
crossAxisOffset = 9
|
||||
crossAxisOffset = 9,
|
||||
disableCloseOnOutsideClick = false,
|
||||
transform = true
|
||||
}: PopperOptions = {}) {
|
||||
const [uncontrolledOpen, setUncontrolledOpen] = React.useState(initialOpen);
|
||||
|
||||
@@ -74,6 +79,7 @@ export function usePopper({
|
||||
open,
|
||||
onOpenChange: setOpen,
|
||||
whileElementsMounted: autoUpdate,
|
||||
transform,
|
||||
middleware: [
|
||||
offset({
|
||||
mainAxis: mainAxisOffset,
|
||||
@@ -98,7 +104,10 @@ export function usePopper({
|
||||
const click = useClick(context, {
|
||||
enabled: controlledOpen == null
|
||||
});
|
||||
const dismiss = useDismiss(context);
|
||||
const dismiss = useDismiss(context, {
|
||||
outsidePress: !disableCloseOnOutsideClick,
|
||||
escapeKey: !disableCloseOnOutsideClick
|
||||
});
|
||||
const role = useRole(context, { role: 'popper' });
|
||||
|
||||
const defaultInteractions = [dismiss, role];
|
||||
@@ -182,11 +191,14 @@ export const PopperTrigger = React.forwardRef<HTMLElement, PopperTriggerProps>(
|
||||
|
||||
export const PopperContent = React.forwardRef<HTMLDivElement, PopperContentProps>(
|
||||
function PopperContent(
|
||||
{ style, headerText, iconRequired = true, noHeader = false, onClose, ...props },
|
||||
{ style, headerText, iconRequired = true, noHeader = false, onClose, className, ...props },
|
||||
propRef
|
||||
) {
|
||||
const context = usePopperContext();
|
||||
const ref = useMergeRefs([context.refs.setFloating, propRef]);
|
||||
const transition = useTransitionStyles(context?.context, {
|
||||
duration: 500
|
||||
});
|
||||
|
||||
const referenceHidden = context?.middlewareData?.hide?.escaped;
|
||||
|
||||
@@ -204,41 +216,45 @@ export const PopperContent = React.forwardRef<HTMLDivElement, PopperContentProps
|
||||
|
||||
return (
|
||||
<FloatingPortal>
|
||||
<div
|
||||
ref={ref}
|
||||
style={{
|
||||
...context.floatingStyles,
|
||||
...style,
|
||||
visibility: referenceHidden ? 'hidden' : 'visible'
|
||||
}}
|
||||
{...context.getFloatingProps(props)}
|
||||
>
|
||||
{!noHeader ? (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
padding: '12px'
|
||||
}}
|
||||
>
|
||||
<div>{headerText}</div>
|
||||
{transition?.isMounted && (
|
||||
<div
|
||||
ref={ref}
|
||||
style={{
|
||||
...context?.floatingStyles,
|
||||
...style,
|
||||
...transition?.styles,
|
||||
visibility: referenceHidden ? 'hidden' : 'visible'
|
||||
}}
|
||||
className={className}
|
||||
{...context?.getFloatingProps(props)}
|
||||
>
|
||||
{!noHeader ? (
|
||||
<div
|
||||
style={{ cursor: 'pointer' }}
|
||||
onClick={() => {
|
||||
if (onClose) onClose();
|
||||
context.setOpen(false);
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
padding: '12px'
|
||||
}}
|
||||
>
|
||||
{iconRequired && <CloseIcon />}
|
||||
<div>{headerText}</div>
|
||||
<div
|
||||
style={{ cursor: 'pointer' }}
|
||||
onClick={() => {
|
||||
if (onClose) onClose();
|
||||
context?.setOpen(false);
|
||||
}}
|
||||
>
|
||||
{iconRequired && <CloseIcon />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{typeof props.children === 'function'
|
||||
? props?.children({ closePopper: closePopper, openPopper: openPopper })
|
||||
: props.children}
|
||||
<FloatingArrow context={context} ref={context?.arrowRef} fill={arrowColor} />
|
||||
</div>
|
||||
) : null}
|
||||
{typeof props.children === 'function'
|
||||
? props?.children({ closePopper: closePopper, openPopper: openPopper })
|
||||
: props.children}
|
||||
<FloatingArrow context={context} ref={context?.arrowRef} fill={arrowColor} />
|
||||
</div>
|
||||
)}
|
||||
</FloatingPortal>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -274,3 +274,22 @@
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
:global {
|
||||
.penaltyPopperWrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--green-dark);
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
color: var(--text-primary);
|
||||
font-family: Inter;
|
||||
font-size: 13px;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 20px;
|
||||
letter-spacing: -0.13px;
|
||||
box-shadow: 0px 6px 10px 0px rgba(0, 0, 0, 0.08), 0px 1px 18px 0px rgba(0, 0, 0, 0.06),
|
||||
0px 3px 5px 0px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { Typography } from '@navi/web-ui/lib/primitives';
|
||||
import { formatAmount } from '@cp/src/utils/commonUtils';
|
||||
import HourGlassIcon from '@cp/src/assets/icons/HourGlassIcon';
|
||||
import HourGlassIcon from '@cp/assets/icons/HourglassIconV2';
|
||||
import cx from 'classnames';
|
||||
import dayjs from 'dayjs';
|
||||
import { EmiFeeActions, IEmiBreakup, PenaltyWaivedLabelMap } from './interfaces';
|
||||
|
||||
@@ -1,26 +1,38 @@
|
||||
import React from 'react';
|
||||
import React, { MutableRefObject } from 'react';
|
||||
import GridContainer from '@navi/web-ui/lib/layouts/Grid/GridContainer/GridContainer';
|
||||
import GridRow from '@navi/web-ui/lib/layouts/Grid/GridRow/GridRow';
|
||||
import { Chip, Typography } from '@navi/web-ui/lib/primitives';
|
||||
import { Checkbox, Tag, Typography } from '@navi/web-ui/lib/primitives';
|
||||
import styles from './AmountdueCard.module.scss';
|
||||
import { formatAmount } from 'src/utils/commonUtils';
|
||||
import cx from 'classnames';
|
||||
import EnachCard from './dc-97/EnachCard';
|
||||
import {
|
||||
HumanReminderType,
|
||||
IHumanReminderDues,
|
||||
MandateStatus,
|
||||
RepaymentFailureDetails,
|
||||
UpcomingDueDetails
|
||||
UpcomingDueDetails,
|
||||
WAIVER_REQUEST_TYPE
|
||||
} from 'src/reducers/commonSlice';
|
||||
import { COLOR_CODING, ColorCoding, DAYS_PAST_DUE } from './dc-97/dc97Constant';
|
||||
import { calculateDateDifferenceInDays, DateFormat, getFormatDate } from '../../utils/DateHelper';
|
||||
import { calculateDateDifferenceInDays } from '../../utils/DateHelper';
|
||||
import useUpdateEffect from '@cp/hooks/useUpdateEffect';
|
||||
import {
|
||||
Popper,
|
||||
PopperContent,
|
||||
PopperContextType,
|
||||
PopperTrigger
|
||||
} from '@cp/components/Popper/Popper';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@cp/components/TooltipV2/TooltipV2';
|
||||
import InfoIconOutlined from '@cp/assets/images/icons/InfoIconOutlined';
|
||||
import HourglassIconV2 from '@cp/assets/icons/HourglassIconV2';
|
||||
|
||||
interface AmountDueCardProps {
|
||||
totalAmount: number;
|
||||
emiDueDate: string;
|
||||
emiAmount: number;
|
||||
emiDaysRemaining: number;
|
||||
emiPenaltyCharge: string;
|
||||
emiPenaltyCharge: string | number;
|
||||
emiIncreasePenaltyChargeDate: string;
|
||||
emiIncreasePenalChargeAmount: number;
|
||||
emiAmountWithIncrementalPenaltyCharge: number;
|
||||
@@ -28,6 +40,14 @@ interface AmountDueCardProps {
|
||||
repaymentFailureDetails: RepaymentFailureDetails;
|
||||
reminderType: HumanReminderType;
|
||||
upcomingDueDetails?: UpcomingDueDetails;
|
||||
totalUnpaidDueAmount: number;
|
||||
totalEmiAmount: number;
|
||||
penaltyApplied: number;
|
||||
nextIncrementAmount: number;
|
||||
paidAmount: number;
|
||||
heldPenaltyCharge: number;
|
||||
holdEligibleDues: IHumanReminderDues;
|
||||
nextDayDues: IHumanReminderDues;
|
||||
}
|
||||
const MANDATE_NOT_SETUP = 'Mandate not set up';
|
||||
|
||||
@@ -65,19 +85,41 @@ const AmountDueCard = (props: AmountDueCardProps) => {
|
||||
repaymentFailureDetails,
|
||||
reminderType,
|
||||
upcomingDueDetails,
|
||||
emiAmountWithIncrementalPenaltyCharge
|
||||
emiAmountWithIncrementalPenaltyCharge,
|
||||
totalUnpaidDueAmount,
|
||||
totalEmiAmount,
|
||||
penaltyApplied,
|
||||
nextIncrementAmount,
|
||||
paidAmount,
|
||||
heldPenaltyCharge,
|
||||
holdEligibleDues,
|
||||
nextDayDues
|
||||
} = props;
|
||||
const upcomingDueDateDiff = calculateDateDifferenceInDays(
|
||||
new Date(),
|
||||
new Date(upcomingDueDetails?.emiDueDate)
|
||||
);
|
||||
const upcomingDueDays = upcomingDueDateDiff > 1 ? DAYS_PAST_DUE.DUE_DAYS : DAYS_PAST_DUE.DUE_DAY;
|
||||
const [slotValue, setSlotValue] = React.useState('');
|
||||
const [showHoldEligibility, setShowHoldEligibility] = React.useState(false);
|
||||
|
||||
const isMandateStatusSuccess = mandateStatus === MandateStatus.SUCCESS;
|
||||
const hideEnachCard = isMandateStatusSuccess && !repaymentFailureDetails?.reason;
|
||||
const enachCardText = repaymentFailureDetails?.reason
|
||||
? repaymentFailureDetails?.reason
|
||||
: MANDATE_NOT_SETUP;
|
||||
const popperTriggerRef = React.useRef<MutableRefObject<PopperContextType>>(null);
|
||||
|
||||
useUpdateEffect(() => {
|
||||
if (showHoldEligibility) {
|
||||
setSlotValue(formatAmount(holdEligibleDues?.totalUnpaidDueAmount?.amount || 0));
|
||||
popperTriggerRef.current?.context?.setOpen(true);
|
||||
} else {
|
||||
popperTriggerRef.current?.context?.setOpen(false);
|
||||
setSlotValue(formatAmount(totalUnpaidDueAmount));
|
||||
}
|
||||
}, [showHoldEligibility]);
|
||||
|
||||
return (
|
||||
<GridContainer
|
||||
className={cx(styles.emiDueContainer, {
|
||||
@@ -111,23 +153,19 @@ const AmountDueCard = (props: AmountDueCardProps) => {
|
||||
)}
|
||||
</span>
|
||||
{emiDaysRemaining && reminderType === HumanReminderType.POST_DUE ? (
|
||||
<span className={styles.topChipText}>since Due Date</span>
|
||||
<span className={styles.topChipText}>since Due Date ({emiDueDate})</span>
|
||||
) : null}
|
||||
</div>
|
||||
<GridRow className={styles.justify_btw}>
|
||||
<Typography variant="h3" className={styles.headingText}>
|
||||
Total Amount Due
|
||||
Total Overdue
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="h3"
|
||||
className={styles.headingValue}
|
||||
color={getDpdColor(emiDaysRemaining, COLOR_CODING.TOTAL_AMOUNT_COLOR, reminderType)}
|
||||
>
|
||||
{reminderType === HumanReminderType.POST_DUE
|
||||
? formatAmount(totalAmount)
|
||||
: reminderType === HumanReminderType.PRE_DUE
|
||||
? formatAmount(upcomingDueDetails?.upcomingPayableDueAmount.amount)
|
||||
: '--'}
|
||||
{totalUnpaidDueAmount ? formatAmount(totalUnpaidDueAmount) : '--'}
|
||||
</Typography>
|
||||
</GridRow>
|
||||
</GridContainer>
|
||||
@@ -141,26 +179,135 @@ const AmountDueCard = (props: AmountDueCardProps) => {
|
||||
<>
|
||||
<GridRow className={cx(styles.emiPenaltyRow, styles.justify_btw)}>
|
||||
<Typography variant="p3" className={styles.emiPenaltyText}>
|
||||
EMI Due Date
|
||||
EMI Amount
|
||||
</Typography>
|
||||
<Typography variant="p3" className={cx(styles.fw700, styles.emiPenaltyValue)}>
|
||||
{emiDueDate}
|
||||
{formatAmount(totalEmiAmount)}
|
||||
</Typography>
|
||||
</GridRow>
|
||||
<GridRow className={cx(styles.emiPenaltyCharge, styles.justify_btw)}>
|
||||
<Typography variant="p3" className={styles.emiPenaltyText}>
|
||||
EMI Penalty Charge
|
||||
EMI Penalty
|
||||
</Typography>
|
||||
<Typography variant="p3" className={cx(styles.fw700, styles.emiPenaltyValue)}>
|
||||
{emiPenaltyCharge}
|
||||
<Typography
|
||||
variant="p3"
|
||||
className={cx(styles.fw700, styles.emiPenaltyValue)}
|
||||
color={typeof emiPenaltyCharge !== 'number' ? 'var(--blue-base)' : ''}
|
||||
>
|
||||
{typeof emiPenaltyCharge === 'number'
|
||||
? formatAmount(emiPenaltyCharge)
|
||||
: emiPenaltyCharge}
|
||||
</Typography>
|
||||
</GridRow>
|
||||
<GridRow className={cx(styles.emiPenaltyRow, styles.justify_btw)}>
|
||||
{(holdEligibleDues || nextDayDues) && (
|
||||
<GridRow className={cx(styles.emiPenaltyCharge, styles.justify_btw)}>
|
||||
<Typography
|
||||
variant="p3"
|
||||
className={cx(styles.emiPenaltyText, 'flex gap-[10px] items-center')}
|
||||
>
|
||||
Penalty Held
|
||||
{nextDayDues ? (
|
||||
<div className={cx('flex', 'gap-[8px]', 'items-center')}>
|
||||
<Tag
|
||||
color="blue"
|
||||
startAdornment={<HourglassIconV2 />}
|
||||
label={`Till 11:59 PM today`}
|
||||
size="sm"
|
||||
variant="transparent"
|
||||
/>
|
||||
<Tooltip placement="top" hiddenPadding={0} hideStrategy="referenceHidden">
|
||||
<TooltipTrigger tooltipTriggerClassName="tooltipTriggerWrapper">
|
||||
<InfoIconOutlined fillColor="var(--blue-base)" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className={styles.tooltipWrapper}>
|
||||
<div className="flex justify-between gap-[20px]">
|
||||
<Typography
|
||||
color="var(--text-primary)"
|
||||
className="text-[13px]"
|
||||
variant="p4"
|
||||
>
|
||||
Total Overdue (Tomorrow)
|
||||
</Typography>
|
||||
<Typography
|
||||
color="var(--text-primary)"
|
||||
className="text-[13px]"
|
||||
variant="p4"
|
||||
>
|
||||
{formatAmount(nextDayDues?.totalUnpaidDueAmount?.amount || 0)}
|
||||
</Typography>
|
||||
</div>
|
||||
<div className="flex justify-between gap-[20px]">
|
||||
<Typography
|
||||
color="var(--text-primary)"
|
||||
className="text-[13px]"
|
||||
variant="p4"
|
||||
>
|
||||
EMI Penalty (Tomorrow)
|
||||
</Typography>
|
||||
<Typography
|
||||
color="var(--text-primary)"
|
||||
className="text-[13px]"
|
||||
variant="p4"
|
||||
>
|
||||
{formatAmount(nextDayDues?.penaltyApplied?.amount || 0)}
|
||||
</Typography>
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
// @TODO : to be added later
|
||||
/* <Checkbox
|
||||
checked={showHoldEligibility}
|
||||
onChange={() => {
|
||||
setShowHoldEligibility(prev => !prev);
|
||||
}}
|
||||
title="Show Hold Eligibility"
|
||||
checkboxTitleClass={cx('text-[var(--blue-base)] font-medium font-[14px]')}
|
||||
/>*/
|
||||
)}
|
||||
</Typography>
|
||||
<Typography variant="p3" className={cx(styles.fw700, styles.emiPenaltyValue)}>
|
||||
<Popper
|
||||
placement="right-end"
|
||||
openOnClick={false}
|
||||
mainAxisOffset={17}
|
||||
crossAxisOffset={5.5}
|
||||
disableCloseOnOutsideClick
|
||||
transform={false}
|
||||
>
|
||||
<PopperTrigger openOnClick={false} ref={popperTriggerRef}>
|
||||
{showHoldEligibility
|
||||
? `${
|
||||
holdEligibleDues?.heldPenaltyCharge?.amount > 0 ? '-' : ''
|
||||
} ${formatAmount(holdEligibleDues?.heldPenaltyCharge?.amount)}`
|
||||
: `${heldPenaltyCharge > 0 ? '-' : ''} ${formatAmount(heldPenaltyCharge)}`}
|
||||
</PopperTrigger>
|
||||
<PopperContent
|
||||
className={cx('penaltyPopperWrapper', 'swing')}
|
||||
arrowColor="var(--green-dark)"
|
||||
noHeader
|
||||
>
|
||||
{holdEligibleDues?.waiverRequestType === WAIVER_REQUEST_TYPE.WAIVER
|
||||
? `Eligible for 100% waiver to close EMI`
|
||||
: 'Eligible for 50% of EMI Penalty'}
|
||||
</PopperContent>
|
||||
</Popper>
|
||||
</Typography>
|
||||
</GridRow>
|
||||
)}
|
||||
|
||||
<GridRow className={cx(styles.emiPenaltyCharge, styles.justify_btw)}>
|
||||
<Typography variant="p3" className={styles.emiPenaltyText}>
|
||||
EMI Amount
|
||||
Paid Amount
|
||||
</Typography>
|
||||
<Typography variant="p3" className={cx(styles.fw700, styles.emiPenaltyValue)}>
|
||||
{formatAmount(emiAmount)}
|
||||
<Typography
|
||||
variant="p3"
|
||||
className={cx(styles.fw700, styles.emiPenaltyValue)}
|
||||
color="var(--green-base)"
|
||||
>
|
||||
- {formatAmount(paidAmount)}
|
||||
</Typography>
|
||||
</GridRow>
|
||||
<GridRow
|
||||
@@ -171,29 +318,18 @@ const AmountDueCard = (props: AmountDueCardProps) => {
|
||||
</GridRow>
|
||||
<GridRow className={cx(styles.emiPenaltyRow, styles.justify_btw)}>
|
||||
<GridRow className={styles.justify_btw} style={{ margin: '0px', padding: '0px' }}>
|
||||
<Typography variant="p3" className={styles.emiPenaltyText}>
|
||||
Upcoming EMI penalty charge
|
||||
<Typography
|
||||
variant="p3"
|
||||
className={cx(styles.emiPenaltyText, 'flex items-center gap-[10px]')}
|
||||
>
|
||||
Upcoming Overdue
|
||||
<Tag
|
||||
color="blue"
|
||||
label={emiIncreasePenaltyChargeDate ? `On ${emiIncreasePenaltyChargeDate}` : ``}
|
||||
size="sm"
|
||||
variant="transparent"
|
||||
/>
|
||||
</Typography>
|
||||
<Chip
|
||||
wrapperClasses={styles.emiPenaltyChip}
|
||||
label={emiIncreasePenaltyChargeDate}
|
||||
></Chip>
|
||||
</GridRow>
|
||||
<GridRow style={{ margin: '0px', padding: '0px' }}>
|
||||
<Typography variant="p3" className={styles.emiPenaltyValue}>
|
||||
{formatAmount(emiIncreasePenalChargeAmount)}
|
||||
</Typography>
|
||||
</GridRow>
|
||||
</GridRow>
|
||||
<GridRow className={cx(styles.emiPenaltyRow, styles.justify_btw)}>
|
||||
<GridRow className={styles.justify_btw} style={{ margin: '0px', padding: '0px' }}>
|
||||
<Typography variant="p3" className={styles.emiPenaltyText}>
|
||||
Upcoming Total Amount Due
|
||||
</Typography>
|
||||
<Chip
|
||||
wrapperClasses={styles.emiPenaltyChip}
|
||||
label={emiIncreasePenaltyChargeDate}
|
||||
></Chip>
|
||||
</GridRow>
|
||||
<GridRow style={{ margin: '0px', padding: '0px' }}>
|
||||
<Typography variant="p3" className={styles.emiPenaltyValue}>
|
||||
@@ -201,25 +337,73 @@ const AmountDueCard = (props: AmountDueCardProps) => {
|
||||
</Typography>
|
||||
</GridRow>
|
||||
</GridRow>
|
||||
<GridRow className={cx(styles.emiPenaltyRow, styles.justify_btw)}>
|
||||
<Typography variant="p3" className={styles.emiPenaltyText}>
|
||||
Upcoming EMI Penalty
|
||||
</Typography>
|
||||
<Typography variant="p3" className={styles.emiPenaltyValue}>
|
||||
{formatAmount(nextIncrementAmount)}
|
||||
</Typography>
|
||||
</GridRow>
|
||||
</>
|
||||
) : reminderType === HumanReminderType.PRE_DUE ? (
|
||||
<>
|
||||
<GridRow className={cx(styles.emiPenaltyRow, styles.justify_btw)}>
|
||||
<Typography variant="p3" className={styles.emiPenaltyText}>
|
||||
Upcoming EMI Due Date
|
||||
EMI Amount
|
||||
</Typography>
|
||||
<Typography variant="p3" className={styles.emiPenaltyValue}>
|
||||
{upcomingDueDetails?.emiDueDate
|
||||
? getFormatDate(new Date(upcomingDueDetails.emiDueDate), DateFormat.DD_MMM_YYYY)
|
||||
: '--'}
|
||||
{formatAmount(totalEmiAmount)}
|
||||
</Typography>
|
||||
</GridRow>
|
||||
<GridRow className={cx(styles.emiPenaltyRow, styles.justify_btw)}>
|
||||
<Typography variant="p3" className={styles.emiPenaltyText}>
|
||||
Upcoming EMI Amount
|
||||
EMI Penalty
|
||||
</Typography>
|
||||
<Typography variant="p3" className={styles.emiPenaltyValue}>
|
||||
{formatAmount(upcomingDueDetails?.upcomingDueAmount.amount)}
|
||||
{formatAmount(penaltyApplied)}
|
||||
</Typography>
|
||||
</GridRow>
|
||||
<GridRow className={cx(styles.emiPenaltyRow, styles.justify_btw)}>
|
||||
<Typography variant="p3" className={styles.emiPenaltyText}>
|
||||
Paid Amount
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="p3"
|
||||
className={cx(styles.emiPenaltyValue, 'font-medium')}
|
||||
color="var(--green-base)"
|
||||
>
|
||||
- {formatAmount(paidAmount)}
|
||||
</Typography>
|
||||
</GridRow>
|
||||
<GridRow
|
||||
style={{ border: '1px dashed #CACED5' }}
|
||||
className={styles.emitPenaltyRowBorder}
|
||||
>
|
||||
{' '}
|
||||
</GridRow>
|
||||
<GridRow className={cx(styles.emiPenaltyRow, styles.justify_btw)}>
|
||||
<Typography variant="p3" className={cx(styles.emiPenaltyText, 'font-medium')}>
|
||||
Upcoming Overdue
|
||||
{emiIncreasePenaltyChargeDate && (
|
||||
<Tag
|
||||
color="blue"
|
||||
label={`On ${emiIncreasePenaltyChargeDate}`}
|
||||
size="sm"
|
||||
variant="transparent"
|
||||
/>
|
||||
)}
|
||||
</Typography>
|
||||
<Typography variant="p3" className={styles.emiPenaltyValue}>
|
||||
{formatAmount(emiAmountWithIncrementalPenaltyCharge)}
|
||||
</Typography>
|
||||
</GridRow>
|
||||
<GridRow className={cx(styles.emiPenaltyRow, styles.justify_btw)}>
|
||||
<Typography variant="p3" className={styles.emiPenaltyText}>
|
||||
Upcoming EMI Penalty
|
||||
</Typography>
|
||||
<Typography variant="p3" className={styles.emiPenaltyValue}>
|
||||
{formatAmount(nextIncrementAmount)}
|
||||
</Typography>
|
||||
</GridRow>
|
||||
</>
|
||||
|
||||
@@ -159,3 +159,17 @@
|
||||
.fw700 {
|
||||
font-weight: 700 !important;
|
||||
}
|
||||
|
||||
.tooltipWrapper {
|
||||
padding: 4px 4px 4px 8px;
|
||||
box-sizing: border-box;
|
||||
width: fit-content;
|
||||
z-index: var(--z-index-tooltip);
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
line-height: 14px;
|
||||
word-wrap: break-word;
|
||||
color: var(--text-primary);
|
||||
border-radius: 4px;
|
||||
background: var(--grayscale-warm-4);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ interface HrCustomerDetailsProps {
|
||||
disConnectHandler: () => void;
|
||||
}
|
||||
|
||||
const emiPenaltyChargeOnHold = 'on hold';
|
||||
const emiPenaltyChargeOnHold = 'On hold';
|
||||
|
||||
const HrCustomerDetails = (props: HrCustomerDetailsProps) => {
|
||||
const { resetCallData, disConnectHandler } = props;
|
||||
@@ -80,9 +80,10 @@ const HrCustomerDetails = (props: HrCustomerDetailsProps) => {
|
||||
const genderAndAge = `${customerDetails?.gender || '--'}, ${customerDetails?.age || '--'}`;
|
||||
const lastUpdatedDue = loanDetails?.unpaidDues?.length ? loanDetails?.unpaidDues[0] : null;
|
||||
const emiPenaltyChargeStatus =
|
||||
lastUpdatedDue?.penaltyCharges?.amount === 0 && lastUpdatedDue?.heldPenaltyCharge?.amount > 0
|
||||
lastUpdatedDue?.unpaidPenaltyCharges?.amount === 0 &&
|
||||
lastUpdatedDue?.heldPenaltyCharge?.amount > 0
|
||||
? emiPenaltyChargeOnHold
|
||||
: formatAmount(lastUpdatedDue?.penaltyCharges?.amount);
|
||||
: lastUpdatedDue?.penaltyApplied?.amount;
|
||||
|
||||
const showFeedbackOptions =
|
||||
loanDetails?.loanAccountNumber && customerDetails?.customerReferenceId;
|
||||
@@ -143,7 +144,7 @@ const HrCustomerDetails = (props: HrCustomerDetailsProps) => {
|
||||
}
|
||||
emiAmount={lastUpdatedDue?.emiAmount?.amount || 0}
|
||||
emiDaysRemaining={loanDetails?.currentDpd || 0}
|
||||
emiPenaltyCharge={emiPenaltyChargeStatus || '--'}
|
||||
emiPenaltyCharge={emiPenaltyChargeStatus || 0}
|
||||
emiIncreasePenaltyChargeDate={
|
||||
lastUpdatedDue?.nextIncrementDate
|
||||
? getFormatDate(new Date(lastUpdatedDue?.nextIncrementDate), DateFormat.DD_MMM_YYYY)
|
||||
@@ -157,6 +158,14 @@ const HrCustomerDetails = (props: HrCustomerDetailsProps) => {
|
||||
repaymentFailureDetails={loanDetails?.repaymentFailureDetails}
|
||||
upcomingDueDetails={loanDetails?.upcomingDueDetails}
|
||||
reminderType={reminderType}
|
||||
totalUnpaidDueAmount={lastUpdatedDue?.totalUnpaidDueAmount?.amount || 0}
|
||||
totalEmiAmount={lastUpdatedDue?.totalEmiAmount?.amount || 0}
|
||||
penaltyApplied={lastUpdatedDue?.penaltyApplied?.amount || 0}
|
||||
nextIncrementAmount={lastUpdatedDue?.nextIncrementAmount?.amount || 0}
|
||||
paidAmount={lastUpdatedDue?.paidAmount?.amount || 0}
|
||||
heldPenaltyCharge={lastUpdatedDue?.heldPenaltyCharge?.amount || 0}
|
||||
holdEligibleDues={loanDetails?.holdEligibilityDues?.[0]}
|
||||
nextDayDues={loanDetails?.nextDayDues?.[0]}
|
||||
/>
|
||||
</div>
|
||||
<SendPaymentLinkCard
|
||||
|
||||
@@ -136,6 +136,57 @@ export interface UpcomingDueDetails {
|
||||
};
|
||||
}
|
||||
|
||||
export enum WAIVER_REQUEST_TYPE {
|
||||
HOLD = 'HOLD',
|
||||
WAIVER = 'WAIVER'
|
||||
}
|
||||
|
||||
export interface IHumanReminderDues {
|
||||
emiDueDate: string;
|
||||
waiverRequestType: WAIVER_REQUEST_TYPE;
|
||||
nextIncrementDate: string;
|
||||
emiAmount: {
|
||||
currency: string;
|
||||
amount: number;
|
||||
};
|
||||
heldPenaltyCharge: {
|
||||
currency: string;
|
||||
amount: number;
|
||||
};
|
||||
penaltyCharges: {
|
||||
currency: string;
|
||||
amount: number;
|
||||
};
|
||||
nextIncrementAmount: {
|
||||
currency: string;
|
||||
amount: number;
|
||||
};
|
||||
emiAmountWithIncrementalPenaltyCharge: {
|
||||
currency: string;
|
||||
amount: number;
|
||||
};
|
||||
totalUnpaidDueAmount: {
|
||||
currency: string;
|
||||
amount: number;
|
||||
};
|
||||
totalEmiAmount: {
|
||||
currency: string;
|
||||
amount: number;
|
||||
};
|
||||
unpaidPenaltyCharges: {
|
||||
currency: string;
|
||||
amount: number;
|
||||
};
|
||||
paidAmount: {
|
||||
currency: string;
|
||||
amount: number;
|
||||
};
|
||||
penaltyApplied: {
|
||||
currency: string;
|
||||
amount: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface HumanReminderCustomerDetails {
|
||||
humanReminderResponse: {
|
||||
customerDetails: {
|
||||
@@ -165,30 +216,9 @@ export interface HumanReminderCustomerDetails {
|
||||
amount: number;
|
||||
};
|
||||
currentDpd: number;
|
||||
unpaidDues: {
|
||||
emiDueDate: string;
|
||||
nextIncrementDate: string;
|
||||
emiAmount: {
|
||||
currency: string;
|
||||
amount: number;
|
||||
};
|
||||
heldPenaltyCharge: {
|
||||
currency: string;
|
||||
amount: number;
|
||||
};
|
||||
penaltyCharges: {
|
||||
currency: string;
|
||||
amount: number;
|
||||
};
|
||||
nextIncrementAmount: {
|
||||
currency: string;
|
||||
amount: number;
|
||||
};
|
||||
emiAmountWithIncrementalPenaltyCharge: {
|
||||
currency: string;
|
||||
amount: number;
|
||||
};
|
||||
}[];
|
||||
unpaidDues: IHumanReminderDues[];
|
||||
holdEligibilityDues: IHumanReminderDues[];
|
||||
nextDayDues: IHumanReminderDues[];
|
||||
mandateStatus: MandateStatus;
|
||||
repaymentFailureDetails: RepaymentFailureDetails;
|
||||
upcomingDueDetails: UpcomingDueDetails;
|
||||
|
||||
Reference in New Issue
Block a user