← back to Goodquestion
src/components/financial/StartupCapitalBreakdown.tsx
263 lines
'use client'
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import {
PieChart,
Pie,
Cell,
BarChart,
Bar,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
Legend,
ResponsiveContainer,
} from 'recharts'
import { DollarSign, ShoppingCart, RefreshCw, TrendingUp, Package } from 'lucide-react'
import type { StartupCosts, AssetItem } from '@/types/swot'
interface StartupCapitalBreakdownProps {
startupCosts: StartupCosts
}
export function StartupCapitalBreakdown({ startupCosts }: StartupCapitalBreakdownProps) {
const formatCurrency = (value: number | undefined) => {
if (value === undefined || value === null || isNaN(value)) {
return '$0'
}
return `$${value.toLocaleString()}`
}
const getPriorityColor = (priority: AssetItem['priority']) => {
switch (priority) {
case 'essential':
return 'destructive'
case 'recommended':
return 'warning'
case 'optional':
return 'secondary'
}
}
const getCategoryIcon = (category: AssetItem['category']) => {
switch (category) {
case 'equipment':
return <Package className="h-4 w-4" />
case 'technology':
return <Package className="h-4 w-4" />
default:
return <ShoppingCart className="h-4 w-4" />
}
}
// Prepare one-time expenses chart data
const oneTimeData = [
{ name: 'Assets', value: startupCosts.oneTimeExpenses.assets.reduce((sum, asset) => sum + (asset.purchasePrice || 0) * asset.quantity, 0) },
{ name: 'Legal Fees', value: startupCosts.oneTimeExpenses.legalFees },
{ name: 'Permits', value: startupCosts.oneTimeExpenses.permits },
{ name: 'Inventory', value: startupCosts.oneTimeExpenses.initialInventory },
{ name: 'Deposits', value: startupCosts.oneTimeExpenses.deposits },
...startupCosts.oneTimeExpenses.other.map(item => ({ name: item.description, value: item.amount })),
].filter(item => item.value > 0)
// Prepare recurring expenses chart data
const recurringData = [
{ name: 'Rent', value: startupCosts.recurringExpenses.rent },
{ name: 'Utilities', value: startupCosts.recurringExpenses.utilities },
{ name: 'Insurance', value: startupCosts.recurringExpenses.insurance },
{ name: 'Payroll', value: startupCosts.recurringExpenses.payroll },
{ name: 'Marketing', value: startupCosts.recurringExpenses.marketing },
...startupCosts.recurringExpenses.other.map(item => ({ name: item.description, value: item.amount })),
].filter(item => item.value > 0)
const COLORS = ['#3b82f6', '#8b5cf6', '#22c55e', '#f59e0b', '#ef4444', '#ec4899', '#14b8a6', '#f97316']
return (
<div className="space-y-6">
{/* Summary Cards */}
<div className="grid md:grid-cols-3 gap-4">
<Card className="border-blue-200 bg-blue-50/50">
<CardHeader className="pb-3">
<CardTitle className="text-sm font-medium flex items-center gap-2 text-blue-700">
<DollarSign className="h-4 w-4" />
Total Startup Capital
</CardTitle>
</CardHeader>
<CardContent>
<div className="text-3xl font-bold text-blue-900">
{formatCurrency(startupCosts.totalStartupCapital)}
</div>
<p className="text-xs text-blue-600 mt-1">One-time investment needed</p>
</CardContent>
</Card>
<Card className="border-orange-200 bg-orange-50/50">
<CardHeader className="pb-3">
<CardTitle className="text-sm font-medium flex items-center gap-2 text-orange-700">
<RefreshCw className="h-4 w-4" />
Monthly Burn Rate
</CardTitle>
</CardHeader>
<CardContent>
<div className="text-3xl font-bold text-orange-900">
{formatCurrency(startupCosts.monthlyBurnRate)}
</div>
<p className="text-xs text-orange-600 mt-1">Recurring monthly expenses</p>
</CardContent>
</Card>
<Card className="border-green-200 bg-green-50/50">
<CardHeader className="pb-3">
<CardTitle className="text-sm font-medium flex items-center gap-2 text-green-700">
<TrendingUp className="h-4 w-4" />
Runway
</CardTitle>
</CardHeader>
<CardContent>
<div className="text-3xl font-bold text-green-900">
{startupCosts.runwayMonths} months
</div>
<p className="text-xs text-green-600 mt-1">Operating runway estimate</p>
</CardContent>
</Card>
</div>
{/* Charts */}
<div className="grid md:grid-cols-2 gap-6">
{/* One-Time Expenses Pie Chart */}
<Card>
<CardHeader>
<CardTitle>One-Time Expenses Breakdown</CardTitle>
<CardDescription>Initial capital requirements</CardDescription>
</CardHeader>
<CardContent>
<ResponsiveContainer width="100%" height={300}>
<PieChart>
<Pie
data={oneTimeData}
cx="50%"
cy="50%"
labelLine={false}
label={({ name, percent }) => `${name}: ${(percent * 100).toFixed(0)}%`}
outerRadius={100}
fill="#8884d8"
dataKey="value"
>
{oneTimeData.map((entry, index) => (
<Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
))}
</Pie>
<Tooltip formatter={(value: any) => formatCurrency(value)} />
</PieChart>
</ResponsiveContainer>
</CardContent>
</Card>
{/* Recurring Expenses Bar Chart */}
<Card>
<CardHeader>
<CardTitle>Monthly Recurring Expenses</CardTitle>
<CardDescription>Ongoing operational costs</CardDescription>
</CardHeader>
<CardContent>
<ResponsiveContainer width="100%" height={300}>
<BarChart data={recurringData}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="name" angle={-45} textAnchor="end" height={100} />
<YAxis tickFormatter={formatCurrency} />
<Tooltip formatter={(value: any) => formatCurrency(value)} />
<Bar dataKey="value" fill="#3b82f6">
{recurringData.map((entry, index) => (
<Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
))}
</Bar>
</BarChart>
</ResponsiveContainer>
</CardContent>
</Card>
</div>
{/* Assets Breakdown */}
<Card>
<CardHeader>
<CardTitle>Required Assets & Equipment</CardTitle>
<CardDescription>
Detailed list of assets needed with purchase and rental options
</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
{startupCosts.oneTimeExpenses.assets.map((asset) => (
<div
key={asset.id}
className="border rounded-lg p-4 hover:shadow-md transition-shadow"
>
<div className="flex items-start justify-between mb-2">
<div className="flex items-start gap-3 flex-1">
<div className="mt-1">{getCategoryIcon(asset.category)}</div>
<div className="flex-1">
<h4 className="font-semibold">{asset.name}</h4>
<p className="text-sm text-muted-foreground mt-1">
{asset.description}
</p>
<div className="flex items-center gap-2 mt-2">
<Badge variant="outline" className="text-xs">
{asset.category}
</Badge>
<Badge variant={getPriorityColor(asset.priority)} className="text-xs">
{asset.priority}
</Badge>
<span className="text-xs text-muted-foreground">
Qty: {asset.quantity}
</span>
</div>
</div>
</div>
</div>
<div className="grid grid-cols-2 gap-4 mt-3 pt-3 border-t">
{asset.purchasePrice && (
<div className={asset.isRental ? 'opacity-50' : ''}>
<div className="text-xs text-muted-foreground mb-1">
Purchase Option
</div>
<div className="text-lg font-bold text-blue-700">
{formatCurrency(asset.purchasePrice * asset.quantity)}
</div>
<div className="text-xs text-muted-foreground">
{formatCurrency(asset.purchasePrice)} × {asset.quantity}
</div>
</div>
)}
{asset.rentalRate && (
<div className={!asset.isRental ? 'opacity-50' : ''}>
<div className="text-xs text-muted-foreground mb-1">
Rental Option
</div>
<div className="text-lg font-bold text-green-700">
{formatCurrency(asset.rentalRate.amount * asset.quantity)}/
{asset.rentalRate.period === 'monthly' ? 'mo' : 'yr'}
</div>
<div className="text-xs text-muted-foreground">
{formatCurrency(asset.rentalRate.amount)} × {asset.quantity}
</div>
</div>
)}
</div>
{asset.isRental && asset.rentalRate && (
<div className="mt-2 text-xs bg-green-50 text-green-700 p-2 rounded">
✓ Recommended: Rental option selected
</div>
)}
</div>
))}
</div>
</CardContent>
</Card>
</div>
)
}