65 lines
1.9 KiB
TypeScript
65 lines
1.9 KiB
TypeScript
import { monthlyPayroll } from '~/types/members'
|
|
|
|
/**
|
|
* Computes months of runway from cash, reserves, and burn rate
|
|
* Formula: (cash + savings) ÷ average monthly burn in scenario
|
|
*/
|
|
export const useRunway = () => {
|
|
const membersStore = useMembersStore()
|
|
const policiesStore = usePoliciesStore()
|
|
const budgetStore = useBudgetStore()
|
|
|
|
const calculateRunway = (cash: number, savings: number, monthlyBurn: number): number => {
|
|
if (monthlyBurn <= 0) return Infinity
|
|
return (cash + savings) / monthlyBurn
|
|
}
|
|
|
|
// Calculate monthly burn based on operating mode
|
|
const getMonthlyBurn = (mode?: 'minimum' | 'target') => {
|
|
const operatingMode = mode || policiesStore.operatingMode || 'minimum'
|
|
|
|
// Get payroll costs based on mode
|
|
const payrollCost = monthlyPayroll(membersStore.members, operatingMode)
|
|
|
|
// Add oncosts
|
|
const oncostPct = policiesStore.payrollOncostPct || 0
|
|
const totalPayroll = Math.round(payrollCost * (1 + oncostPct / 100))
|
|
|
|
// Add overhead costs
|
|
const overheadCost = budgetStore.overheadCosts.reduce((sum, cost) => sum + (cost.amount || 0), 0)
|
|
|
|
return totalPayroll + overheadCost
|
|
}
|
|
|
|
// Calculate runway for both modes
|
|
const getDualModeRunway = (cash: number, savings: number) => {
|
|
const minBurn = getMonthlyBurn('minimum')
|
|
const targetBurn = getMonthlyBurn('target')
|
|
|
|
return {
|
|
minimum: calculateRunway(cash, savings, minBurn),
|
|
target: calculateRunway(cash, savings, targetBurn),
|
|
minBurn,
|
|
targetBurn
|
|
}
|
|
}
|
|
|
|
const getRunwayStatus = (months: number): 'green' | 'yellow' | 'red' => {
|
|
if (months >= 3) return 'green'
|
|
if (months >= 2) return 'yellow'
|
|
return 'red'
|
|
}
|
|
|
|
const formatRunway = (months: number): string => {
|
|
if (months === Infinity) return '∞ months'
|
|
return `${months.toFixed(1)} months`
|
|
}
|
|
|
|
return {
|
|
calculateRunway,
|
|
getRunwayStatus,
|
|
formatRunway,
|
|
getMonthlyBurn,
|
|
getDualModeRunway
|
|
}
|
|
}
|