152 lines
4.0 KiB
TypeScript
152 lines
4.0 KiB
TypeScript
/**
|
|
* Utility functions for Flow Funding calculations
|
|
*/
|
|
|
|
import type { FlowFundingAccount, AccountStatus, FlowFundingNetwork, Allocation } from './types'
|
|
|
|
/**
|
|
* Calculate account status based on balance vs thresholds
|
|
*/
|
|
export function getAccountStatus(account: FlowFundingAccount): AccountStatus {
|
|
if (account.balance < account.minThreshold) return 'deficit'
|
|
if (account.balance >= account.maxThreshold) return 'overflow'
|
|
if (Math.abs(account.balance - account.minThreshold) < 0.01) return 'minimum'
|
|
return 'healthy'
|
|
}
|
|
|
|
/**
|
|
* Calculate shortfall (funds needed to reach minimum)
|
|
*/
|
|
export function calculateShortfall(account: FlowFundingAccount): number {
|
|
return Math.max(0, account.minThreshold - account.balance)
|
|
}
|
|
|
|
/**
|
|
* Calculate capacity (funds that can be added before reaching maximum)
|
|
*/
|
|
export function calculateCapacity(account: FlowFundingAccount): number {
|
|
return Math.max(0, account.maxThreshold - account.balance)
|
|
}
|
|
|
|
/**
|
|
* Calculate overflow (funds beyond maximum threshold)
|
|
*/
|
|
export function calculateOverflow(account: FlowFundingAccount): number {
|
|
return Math.max(0, account.balance - account.maxThreshold)
|
|
}
|
|
|
|
/**
|
|
* Update computed properties on an account
|
|
*/
|
|
export function updateAccountComputedProperties(
|
|
account: FlowFundingAccount
|
|
): FlowFundingAccount {
|
|
return {
|
|
...account,
|
|
status: getAccountStatus(account),
|
|
shortfall: calculateShortfall(account),
|
|
capacity: calculateCapacity(account),
|
|
overflow: calculateOverflow(account),
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calculate network-level totals
|
|
*/
|
|
export function calculateNetworkTotals(network: FlowFundingNetwork): FlowFundingNetwork {
|
|
const totalFunds = network.accounts.reduce((sum, acc) => sum + acc.balance, 0)
|
|
const totalShortfall = network.accounts.reduce((sum, acc) => sum + acc.shortfall, 0)
|
|
const totalCapacity = network.accounts.reduce((sum, acc) => sum + acc.capacity, 0)
|
|
const totalOverflow = network.accounts.reduce((sum, acc) => sum + acc.overflow, 0)
|
|
|
|
return {
|
|
...network,
|
|
totalFunds,
|
|
totalShortfall,
|
|
totalCapacity,
|
|
totalOverflow,
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Normalize allocations so they sum to 1.0
|
|
*/
|
|
export function normalizeAllocations(allocations: Allocation[]): Allocation[] {
|
|
// If only one allocation, it must be 100%
|
|
if (allocations.length === 1) {
|
|
return allocations.map(a => ({ ...a, percentage: 1.0 }))
|
|
}
|
|
|
|
const total = allocations.reduce((sum, a) => sum + a.percentage, 0)
|
|
|
|
// If total is 0, distribute equally
|
|
if (total === 0) {
|
|
const equalShare = 1.0 / allocations.length
|
|
return allocations.map((a) => ({
|
|
...a,
|
|
percentage: equalShare,
|
|
}))
|
|
}
|
|
|
|
// If already normalized (within tolerance), return as-is
|
|
if (Math.abs(total - 1.0) < 0.0001) {
|
|
return allocations
|
|
}
|
|
|
|
// Normalize by dividing by total
|
|
return allocations.map((a) => ({
|
|
...a,
|
|
percentage: a.percentage / total,
|
|
}))
|
|
}
|
|
|
|
/**
|
|
* Get center point of an account (for arrow endpoints)
|
|
*/
|
|
export function getAccountCenter(account: FlowFundingAccount): { x: number; y: number } {
|
|
return {
|
|
x: account.x + account.width / 2,
|
|
y: account.y + account.height / 2,
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get status color for rendering
|
|
*/
|
|
export function getStatusColor(status: AccountStatus, alpha: number = 1): string {
|
|
const colors = {
|
|
deficit: `rgba(239, 68, 68, ${alpha})`, // Red
|
|
minimum: `rgba(251, 191, 36, ${alpha})`, // Yellow
|
|
healthy: `rgba(99, 102, 241, ${alpha})`, // Blue
|
|
overflow: `rgba(16, 185, 129, ${alpha})`, // Green
|
|
}
|
|
return colors[status]
|
|
}
|
|
|
|
/**
|
|
* Get status color as Tailwind class
|
|
*/
|
|
export function getStatusColorClass(status: AccountStatus): string {
|
|
const classes = {
|
|
deficit: 'text-red-400',
|
|
minimum: 'text-yellow-400',
|
|
healthy: 'text-blue-400',
|
|
overflow: 'text-green-400',
|
|
}
|
|
return classes[status]
|
|
}
|
|
|
|
/**
|
|
* Format currency for display
|
|
*/
|
|
export function formatCurrency(amount: number): string {
|
|
return amount.toFixed(0)
|
|
}
|
|
|
|
/**
|
|
* Format percentage for display
|
|
*/
|
|
export function formatPercentage(decimal: number): string {
|
|
return `${Math.round(decimal * 100)}%`
|
|
}
|