Files
edr-platform/apps/edr-passenger-web/portal/src/utils/fare-utils.ts

108 lines
3.0 KiB
TypeScript

/**
* Utility functions for age-based fare calculations
* Implements the "first child free" pricing policy
*/
export interface PassengerWithAge {
dateOfBirth?: string;
name?: string;
}
/**
* Calculate age from date of birth
*/
export function calculateAge(dateOfBirth: string | Date): number {
const today = new Date();
const birth = new Date(dateOfBirth);
let age = today.getFullYear() - birth.getFullYear();
const monthDiff = today.getMonth() - birth.getMonth();
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
age--;
}
return Math.max(0, age);
}
/**
* Check if passenger is a child (under 5 years old)
*/
export function isChild(passenger: PassengerWithAge): boolean {
if (!passenger.dateOfBirth) return false;
return calculateAge(passenger.dateOfBirth) < 5;
}
/**
* Check if this child gets a free fare (1 free child per adult)
*/
export function isFirstChild(passengers: PassengerWithAge[], currentIndex: number): boolean {
const currentPassenger = passengers[currentIndex];
if (!isChild(currentPassenger)) return false;
const adultCount = passengers.filter(p => !isChild(p)).length;
const childrenBefore = passengers.slice(0, currentIndex).filter(p => isChild(p));
return childrenBefore.length < adultCount;
}
/**
* Calculate fare for a single passenger with first child free logic
*/
export function calculatePassengerFare(
passengers: PassengerWithAge[],
passengerIndex: number,
baseFare: number
): number {
const passenger = passengers[passengerIndex];
if (isChild(passenger) && isFirstChild(passengers, passengerIndex)) {
return 0; // First child travels free
}
return baseFare;
}
/**
* Calculate total fare for all passengers with first child free logic
*/
export function calculateTotalFare(
passengers: PassengerWithAge[],
baseFare: number
): number {
return passengers.reduce((total, _, index) => {
return total + calculatePassengerFare(passengers, index, baseFare);
}, 0);
}
/**
* Get passenger category for display purposes
*/
export function getPassengerCategory(passenger: PassengerWithAge): 'ADULT' | 'CHILD' {
return isChild(passenger) ? 'CHILD' : 'ADULT';
}
/**
* Format fare amount for display
*/
export function formatFare(amountMinor: number, currency: string = 'ETB'): string {
return `${currency} ${(amountMinor / 100).toFixed(2)}`;
}
/**
* Get pricing summary for a list of passengers
*/
export function getPricingSummary(passengers: PassengerWithAge[], baseFare: number) {
const adults = passengers.filter(p => !isChild(p));
const children = passengers.filter(p => isChild(p));
const freeChildren = Math.min(children.length, adults.length);
const paidChildren = Math.max(0, children.length - adults.length);
return {
adultCount: adults.length,
childCount: children.length,
freeChildrenCount: freeChildren,
paidChildrenCount: paidChildren,
adultFare: adults.length * baseFare,
paidChildFare: paidChildren * baseFare,
totalFare: calculateTotalFare(passengers, baseFare)
};
}