app/pages/project-budget.vue

84 lines
No EOL
3.2 KiB
Vue

<template>
<div class="space-y-8">
<div class="text-center">
<h1 class="text-3xl font-bold mb-4">Project Budget Estimate</h1>
<p class="text-neutral-600 max-w-2xl mx-auto mb-4">
Get a quick estimate of what it would cost to build your project with fair pay.
This tool helps worker co-ops sketch project budgets and break-even scenarios.
</p>
<div class="bg-blue-50 border border-blue-200 rounded-lg p-4 max-w-2xl mx-auto">
<div class="flex items-start gap-2">
<UIcon name="i-heroicons-information-circle" class="h-5 w-5 text-blue-500 mt-0.5 flex-shrink-0" />
<div class="text-sm text-blue-800">
<p class="font-medium mb-1">About the calculations:</p>
<p>These estimates are based on <strong>sustainable payroll</strong> what you can actually afford to pay based on your revenue minus overhead costs. This may be different from theoretical maximum wages if revenue is limited.</p>
</div>
</div>
</div>
</div>
<div v-if="membersWithPay.length === 0" class="text-center py-8">
<p class="text-neutral-600 mb-4">No team members set up yet.</p>
<NuxtLink
to="/coop-builder"
class="px-4 py-2 border-2 border-black bg-white font-bold hover:bg-neutral-100"
>
Set up your team in Setup Wizard
</NuxtLink>
</div>
<ProjectBudgetEstimate
v-else
:members="membersWithPay"
:oncost-rate="coopStore.payrollOncostPct / 100"
/>
</div>
</template>
<script setup lang="ts">
const coopStore = useCoopBuilderStore()
const budgetStore = useBudgetStore()
// Calculate member pay using the same allocation logic as the budget system
const membersWithPay = computed(() => {
// Get current month's payroll from budget store (matches budget page)
const today = new Date()
const currentMonthKey = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, "0")}`
const payrollExpense = budgetStore.budgetWorksheet.expenses.find(item =>
item.id === "expense-payroll-base" || item.id === "expense-payroll"
)
const actualPayrollBudget = payrollExpense?.monthlyValues?.[currentMonthKey] || 0
// Use the member's desired hours (targetHours if available, otherwise hoursPerMonth)
const getHoursForMember = (member: any) => {
return member.capacity?.targetHours || member.hoursPerMonth || 0
}
// Get theoretical allocation then scale to actual budget
const { allocatePayroll } = useCoopBuilder()
const theoreticalMembers = allocatePayroll()
const theoreticalTotal = theoreticalMembers.reduce((sum, m) => sum + (m.monthlyPayPlanned || 0), 0)
const scaleFactor = theoreticalTotal > 0 ? actualPayrollBudget / theoreticalTotal : 0
const allocatedMembers = theoreticalMembers.map(member => ({
...member,
monthlyPayPlanned: (member.monthlyPayPlanned || 0) * scaleFactor
}))
return allocatedMembers.map(member => {
const hours = getHoursForMember(member)
return {
name: member.name || 'Unnamed',
hoursPerMonth: hours,
monthlyPay: member.monthlyPayPlanned || 0
}
}).filter(m => m.hoursPerMonth > 0) // Only include members with hours
})
// Set page meta
definePageMeta({
title: 'Project Budget Estimate'
})
</script>