Fix form keyboard issues and sticky footers in agent screens
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
import type {
|
||||
DepositAccount,
|
||||
DepositInterestPayoutType,
|
||||
DepositStatus,
|
||||
} from '../../../types/app';
|
||||
|
||||
const MS_PER_DAY = 1000 * 60 * 60 * 24;
|
||||
|
||||
const clamp = (value: number, min: number, max: number) =>
|
||||
Math.min(Math.max(value, min), max);
|
||||
|
||||
export const calculateFixedDepositMaturity = (
|
||||
principal: number,
|
||||
annualRate: number,
|
||||
tenureMonths: number,
|
||||
payoutType: DepositInterestPayoutType = 'cumulative',
|
||||
) => {
|
||||
if (principal <= 0 || annualRate <= 0 || tenureMonths <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const years = tenureMonths / 12;
|
||||
|
||||
if (payoutType === 'non-cumulative') {
|
||||
return principal + principal * (annualRate / 100) * years;
|
||||
}
|
||||
|
||||
const quarterlyRate = annualRate / 100 / 4;
|
||||
const periods = years * 4;
|
||||
|
||||
return principal * Math.pow(1 + quarterlyRate, periods);
|
||||
};
|
||||
|
||||
export const calculateRecurringDepositMaturity = (
|
||||
monthlyInstallment: number,
|
||||
annualRate: number,
|
||||
tenureMonths: number,
|
||||
) => {
|
||||
if (monthlyInstallment <= 0 || annualRate <= 0 || tenureMonths <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const monthlyRate = annualRate / 100 / 12;
|
||||
let maturityAmount = 0;
|
||||
|
||||
for (let month = 0; month < tenureMonths; month += 1) {
|
||||
maturityAmount += monthlyInstallment * Math.pow(1 + monthlyRate, tenureMonths - month);
|
||||
}
|
||||
|
||||
return maturityAmount;
|
||||
};
|
||||
|
||||
export const getDepositCanonicalStatus = (
|
||||
deposit: Pick<DepositAccount, 'status' | 'maturityDate'>,
|
||||
now = new Date(),
|
||||
): DepositStatus => {
|
||||
if (deposit.status === 'closed') {
|
||||
return 'closed';
|
||||
}
|
||||
|
||||
return new Date(deposit.maturityDate).getTime() <= now.getTime() ? 'matured' : 'active';
|
||||
};
|
||||
|
||||
export const getDaysUntilMaturity = (maturityDate: string, now = new Date()) => {
|
||||
const diff = new Date(maturityDate).getTime() - now.getTime();
|
||||
|
||||
return Math.ceil(diff / MS_PER_DAY);
|
||||
};
|
||||
|
||||
export const isDepositNearMaturity = (
|
||||
deposit: Pick<DepositAccount, 'status' | 'maturityDate'>,
|
||||
now = new Date(),
|
||||
) => {
|
||||
const daysUntilMaturity = getDaysUntilMaturity(deposit.maturityDate, now);
|
||||
|
||||
return getDepositCanonicalStatus(deposit, now) === 'active' && daysUntilMaturity <= 7;
|
||||
};
|
||||
|
||||
export const getDepositProgress = (
|
||||
startDate: string,
|
||||
maturityDate: string,
|
||||
now = new Date(),
|
||||
) => {
|
||||
const start = new Date(startDate).getTime();
|
||||
const maturity = new Date(maturityDate).getTime();
|
||||
const current = now.getTime();
|
||||
|
||||
if (maturity <= start) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return clamp((current - start) / (maturity - start), 0, 1);
|
||||
};
|
||||
|
||||
export const calculatePrematureClosureAmount = (
|
||||
deposit: Pick<
|
||||
DepositAccount,
|
||||
'kind' | 'principalAmount' | 'monthlyInstallment' | 'interestRate' | 'startDate' | 'maturityDate' | 'maturityAmount' | 'prematurePenaltyRate' | 'status'
|
||||
>,
|
||||
now = new Date(),
|
||||
) => {
|
||||
const canonicalStatus = getDepositCanonicalStatus(deposit, now);
|
||||
|
||||
if (canonicalStatus === 'closed') {
|
||||
return {
|
||||
penaltyAmount: 0,
|
||||
netAmount: deposit.maturityAmount,
|
||||
};
|
||||
}
|
||||
|
||||
if (canonicalStatus === 'matured') {
|
||||
return {
|
||||
penaltyAmount: 0,
|
||||
netAmount: deposit.maturityAmount,
|
||||
};
|
||||
}
|
||||
|
||||
const elapsedMonths = Math.max(
|
||||
1,
|
||||
Math.round((now.getTime() - new Date(deposit.startDate).getTime()) / (MS_PER_DAY * 30)),
|
||||
);
|
||||
|
||||
const currentValue =
|
||||
deposit.kind === 'fd'
|
||||
? calculateFixedDepositMaturity(
|
||||
deposit.principalAmount,
|
||||
deposit.interestRate,
|
||||
elapsedMonths,
|
||||
'non-cumulative',
|
||||
)
|
||||
: calculateRecurringDepositMaturity(
|
||||
deposit.monthlyInstallment ?? 0,
|
||||
deposit.interestRate,
|
||||
elapsedMonths,
|
||||
);
|
||||
const investedBase =
|
||||
deposit.kind === 'fd'
|
||||
? deposit.principalAmount
|
||||
: (deposit.monthlyInstallment ?? 0) * elapsedMonths;
|
||||
|
||||
const penaltyAmount = currentValue * ((deposit.prematurePenaltyRate ?? 0) / 100);
|
||||
|
||||
return {
|
||||
penaltyAmount,
|
||||
netAmount: Math.max(currentValue - penaltyAmount, investedBase * 0.9),
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user