Files
NeoCom/src/app/(dashboard)/finance/capital-markets/page.tsx
2026-04-09 20:36:10 -07:00

854 lines
36 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import { useState, useEffect } from 'react';
import { formatCurrency, formatCompactCurrency } from '@/lib/utils';
import {
TrendingUp,
DollarSign,
Percent,
Calendar,
Plus,
Loader2,
AlertCircle,
CheckCircle,
Zap,
ChevronDown,
ChevronUp,
} from 'lucide-react';
interface DebtFacility {
id: string;
name: string;
lender: string;
type: 'Revolving Credit' | 'Term Loan' | 'Line of Credit' | 'Equipment Financing' | 'Other';
commitmentAmount: number;
drawnAmount: number;
availableAmount: number;
interestRate: string;
maturityDate: string;
status: 'Active' | 'Inactive' | 'Closed';
draws: DebtDraw[];
}
interface DebtDraw {
id: string;
facilityId: string;
drawDate: string;
amount: number;
repaymentDate: string | null;
status: 'Active' | 'Repaid' | 'Partial';
interestRate: string;
}
interface Covenant {
id: string;
name: string;
type: string;
metric: string;
threshold: string | number;
currentValue: string | number;
status: 'Compliant' | 'Warning' | 'Breach';
lastChecked: string;
headroom: string;
}
interface NewFacilityForm {
name: string;
lender: string;
type: 'Revolving Credit' | 'Term Loan' | 'Line of Credit' | 'Equipment Financing' | 'Other';
commitmentAmount: string;
interestRate: string;
maturityDate: string;
}
interface NewDrawForm {
facilityId: string;
amount: string;
date: string;
interestRate: string;
}
interface Toast {
id: string;
message: string;
type: 'success' | 'error' | 'info';
}
export default function CapitalMarketsPage() {
const [loading, setLoading] = useState(true);
const [activeTab, setActiveTab] = useState('facilities');
const [showNewFacility, setShowNewFacility] = useState(false);
const [showRecordDraw, setShowRecordDraw] = useState(false);
const [expandedFacilityId, setExpandedFacilityId] = useState<string | null>(null);
const [toasts, setToasts] = useState<Toast[]>([]);
const [facilities, setFacilities] = useState<DebtFacility[]>([]);
const [draws, setDraws] = useState<DebtDraw[]>([]);
const [covenants, setCovenants] = useState<Covenant[]>([]);
const [newFacilityForm, setNewFacilityForm] = useState<NewFacilityForm>({
name: '',
lender: '',
type: 'Revolving Credit',
commitmentAmount: '',
interestRate: '',
maturityDate: '',
});
const [newDrawForm, setNewDrawForm] = useState<NewDrawForm>({
facilityId: '',
amount: '',
date: new Date().toISOString().split('T')[0],
interestRate: '',
});
const [summary, setSummary] = useState({
totalDebtOutstanding: 0,
totalAvailable: 0,
weightedAvgRate: 0,
nextMaturityDate: null as string | null,
covenantStatus: 'All Clear',
});
// Toast helper
const addToast = (message: string, type: 'success' | 'error' | 'info' = 'info') => {
const id = Math.random().toString(36).substring(7);
setToasts((prev) => [...prev, { id, message, type }]);
setTimeout(() => {
setToasts((prev) => prev.filter((t) => t.id !== id));
}, 4000);
};
// Fetch data from API
useEffect(() => {
const fetchData = async () => {
try {
setLoading(true);
const res = await fetch('/api/capital-markets');
if (!res.ok) throw new Error('Failed to fetch capital markets data');
const data = await res.json();
setFacilities(data.facilities);
setDraws(data.draws);
setCovenants(data.covenants);
setSummary({
totalDebtOutstanding: data.summary?.totalOutstanding ?? 0,
totalAvailable: data.summary?.totalAvailable ?? 0,
weightedAvgRate: data.summary?.weightedAvgRate ?? 0,
nextMaturityDate: data.summary?.nextMaturityDate ?? '',
covenantStatus: data.summary?.covenantStatus ?? 'Unknown',
});
} catch (err) {
console.error('Error fetching capital markets data:', err);
addToast('Failed to fetch capital markets data', 'error');
} finally {
setLoading(false);
}
};
fetchData();
}, []);
const handleAddFacility = async () => {
if (!newFacilityForm.name || !newFacilityForm.lender || !newFacilityForm.commitmentAmount || !newFacilityForm.interestRate || !newFacilityForm.maturityDate) {
addToast('Please fill in all required fields', 'error');
return;
}
try {
setLoading(true);
const res = await fetch('/api/capital-markets', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'create-facility',
facility: newFacilityForm,
}),
});
if (!res.ok) {
const error = await res.json();
throw new Error(error.error || 'Failed to create facility');
}
// Reset form and close modal
setNewFacilityForm({
name: '',
lender: '',
type: 'Revolving Credit',
commitmentAmount: '',
interestRate: '',
maturityDate: '',
});
setShowNewFacility(false);
addToast('Facility created successfully', 'success');
// Refetch data to keep in sync
const refreshRes = await fetch('/api/capital-markets');
if (refreshRes.ok) {
const refreshData = await refreshRes.json();
setFacilities(refreshData.facilities);
setDraws(refreshData.draws);
setCovenants(refreshData.covenants);
setSummary({
totalDebtOutstanding: refreshData.summary.totalOutstanding,
totalAvailable: refreshData.summary.totalAvailable,
weightedAvgRate: refreshData.summary.weightedAvgRate,
nextMaturityDate: refreshData.summary.nextMaturityDate,
covenantStatus: refreshData.summary.covenantStatus,
});
}
} catch (err) {
console.error('Error adding facility:', err);
addToast(err instanceof Error ? err.message : 'Failed to create facility', 'error');
} finally {
setLoading(false);
}
};
const handleRecordDraw = async () => {
if (!newDrawForm.facilityId || !newDrawForm.amount) {
addToast('Please select a facility and enter an amount', 'error');
return;
}
try {
setLoading(true);
const res = await fetch('/api/capital-markets', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'record-draw',
draw: newDrawForm,
}),
});
if (!res.ok) {
const error = await res.json();
throw new Error(error.error || 'Failed to record draw');
}
setNewDrawForm({
facilityId: '',
amount: '',
date: new Date().toISOString().split('T')[0],
interestRate: '',
});
setShowRecordDraw(false);
addToast('Draw recorded successfully', 'success');
// Refetch data to keep in sync
const refreshRes = await fetch('/api/capital-markets');
if (refreshRes.ok) {
const refreshData = await refreshRes.json();
setFacilities(refreshData.facilities);
setDraws(refreshData.draws);
setCovenants(refreshData.covenants);
setSummary({
totalDebtOutstanding: refreshData.summary.totalOutstanding,
totalAvailable: refreshData.summary.totalAvailable,
weightedAvgRate: refreshData.summary.weightedAvgRate,
nextMaturityDate: refreshData.summary.nextMaturityDate,
covenantStatus: refreshData.summary.covenantStatus,
});
}
} catch (err) {
console.error('Error recording draw:', err);
addToast(err instanceof Error ? err.message : 'Failed to record draw', 'error');
} finally {
setLoading(false);
}
};
function formatDate(dateStr: string) {
return new Date(dateStr).toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
});
}
const getCovenanStatusColor = (status: string) => {
switch (status) {
case 'Compliant':
return 'bg-green-900/25 text-green-800 border-green-200';
case 'Warning':
return 'bg-yellow-900/25 text-yellow-400 border-yellow-500/25';
case 'Breach':
return 'bg-red-900/25 text-red-800 border-red-200';
default:
return 'bg-[#1A1A1F] text-[#F0F0F3] border-[#2A2A32]';
}
};
const getCovenanStatusIcon = (status: string) => {
switch (status) {
case 'Compliant':
return <CheckCircle size={16} />;
case 'Warning':
return <AlertCircle size={16} />;
case 'Breach':
return <AlertCircle size={16} />;
default:
return null;
}
};
const getCovenantSummaryBadge = () => {
const status = summary.covenantStatus;
if (status === 'In Breach') {
return <span className="inline-block px-3 py-1 rounded-full text-xs font-semibold bg-red-900/25 text-red-800 border border-red-200">In Breach</span>;
} else if (status === 'At Risk') {
return <span className="inline-block px-3 py-1 rounded-full text-xs font-semibold bg-yellow-900/25 text-yellow-400 border border-yellow-500/25">At Risk</span>;
} else {
return <span className="inline-block px-3 py-1 rounded-full text-xs font-semibold bg-green-900/25 text-green-800 border border-green-200">All Clear</span>;
}
};
if (loading && facilities.length === 0) {
return (
<div className="flex items-center justify-center min-h-screen">
<Loader2 className="animate-spin" size={32} />
</div>
);
}
return (
<div className="min-h-screen bg-[#111114] p-8">
{/* Toast Notifications */}
<div className="fixed top-4 right-4 z-50 space-y-2">
{toasts.map((toast) => (
<div
key={toast.id}
className={`px-4 py-3 rounded-lg text-sm font-medium shadow-lg ${
toast.type === 'success'
? 'bg-green-500 text-white'
: toast.type === 'error'
? 'bg-red-500 text-white'
: 'bg-blue-500 text-white'
}`}
>
{toast.message}
</div>
))}
</div>
<div className="max-w-7xl mx-auto">
{/* Header */}
<div className="flex justify-between items-start mb-8">
<div>
<h1 className="text-4xl font-bold text-[#F0F0F3] mb-2">Capital Markets</h1>
<p className="text-lg text-[#8B8B9E]">Debt Management, Credit Facilities & Covenant Compliance</p>
</div>
<div className="flex gap-4">
<button
onClick={() => setShowNewFacility(true)}
className="flex items-center gap-2 bg-blue-600 text-white px-6 py-2.5 rounded-lg hover:bg-blue-700 transition-colors font-medium"
>
<Plus size={18} />
New Facility
</button>
<button
onClick={() => setShowRecordDraw(true)}
className="flex items-center gap-2 bg-green-600 text-white px-6 py-2.5 rounded-lg hover:bg-green-700 transition-colors font-medium"
>
<DollarSign size={18} />
Record Draw
</button>
</div>
</div>
{/* Summary Cards */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-6 mb-8">
<div className="bg-[#1A1A1F] rounded-lg border border-[#2A2A32] p-6" title={formatCurrency(summary.totalDebtOutstanding)}>
<div className="flex items-center justify-between mb-4">
<div className="bg-blue-900/25 p-3 rounded-lg">
<TrendingUp className="w-6 h-6 text-blue-600" />
</div>
</div>
<p className="text-sm font-medium text-[#8B8B9E]">Total Debt Outstanding</p>
<p className="text-2xl font-bold text-[#F0F0F3] mt-2">{formatCompactCurrency(summary.totalDebtOutstanding)}</p>
<p className="text-xs text-[#8B8B9E] mt-1">Across {facilities.length} facilities</p>
</div>
<div className="bg-[#1A1A1F] rounded-lg border border-[#2A2A32] p-6" title={formatCurrency(summary.totalAvailable)}>
<div className="flex items-center justify-between mb-4">
<div className="bg-green-900/25 p-3 rounded-lg">
<DollarSign className="w-6 h-6 text-green-600" />
</div>
</div>
<p className="text-sm font-medium text-[#8B8B9E]">Available Credit</p>
<p className="text-2xl font-bold text-[#F0F0F3] mt-2">{formatCompactCurrency(summary.totalAvailable)}</p>
<p className="text-xs text-[#8B8B9E] mt-1">Ready to draw</p>
</div>
<div className="bg-[#1A1A1F] rounded-lg border border-[#2A2A32] p-6">
<div className="flex items-center justify-between mb-4">
<div className="bg-orange-900/25 p-3 rounded-lg">
<Percent className="w-6 h-6 text-orange-600" />
</div>
</div>
<p className="text-sm font-medium text-[#8B8B9E]">Weighted Avg Rate</p>
<p className="text-2xl font-bold text-[#F0F0F3] mt-2">{summary.weightedAvgRate.toFixed(2)}%</p>
<p className="text-xs text-[#8B8B9E] mt-1">All active facilities</p>
</div>
<div className="bg-[#1A1A1F] rounded-lg border border-[#2A2A32] p-6">
<div className="flex items-center justify-between mb-4">
<div className="bg-purple-900/25 p-3 rounded-lg">
<Calendar className="w-6 h-6 text-purple-600" />
</div>
</div>
<p className="text-sm font-medium text-[#8B8B9E]">Next Maturity</p>
<p className="text-2xl font-bold text-[#F0F0F3] mt-2">
{summary.nextMaturityDate ? formatDate(summary.nextMaturityDate) : 'N/A'}
</p>
<p className="text-xs text-[#8B8B9E] mt-1">Upcoming refinancing</p>
</div>
<div className="bg-[#1A1A1F] rounded-lg border border-[#2A2A32] p-6">
<div className="flex items-center justify-between mb-4">
<div className="bg-indigo-900/15 p-3 rounded-lg">
<Zap className="w-6 h-6 text-indigo-600" />
</div>
</div>
<p className="text-sm font-medium text-[#8B8B9E]">Covenant Status</p>
<div className="mt-2">
{getCovenantSummaryBadge()}
</div>
</div>
</div>
{/* New Facility Form */}
{showNewFacility && (
<div className="bg-[#1A1A1F] rounded-lg border border-[#2A2A32] p-6 mb-8">
<div className="flex items-center justify-between mb-6">
<h3 className="text-lg font-semibold text-[#F0F0F3]">New Debt Facility</h3>
<button
onClick={() => setShowNewFacility(false)}
className="text-[#5A5A6E] hover:text-[#8B8B9E] text-2xl font-light"
>
×
</button>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
<div>
<label className="block text-sm font-medium text-[#8B8B9E] mb-1">Facility Name *</label>
<input
type="text"
value={newFacilityForm.name}
onChange={(e) => setNewFacilityForm({ ...newFacilityForm, name: e.target.value })}
className="w-full px-3 py-2 border border-[#3A3A45] rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="e.g., Tech Bank Credit Line"
/>
</div>
<div>
<label className="block text-sm font-medium text-[#8B8B9E] mb-1">Lender *</label>
<input
type="text"
value={newFacilityForm.lender}
onChange={(e) => setNewFacilityForm({ ...newFacilityForm, lender: e.target.value })}
className="w-full px-3 py-2 border border-[#3A3A45] rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="e.g., JP Morgan Chase"
/>
</div>
<div>
<label className="block text-sm font-medium text-[#8B8B9E] mb-1">Type *</label>
<select
value={newFacilityForm.type}
onChange={(e) => setNewFacilityForm({ ...newFacilityForm, type: e.target.value as any })}
className="w-full px-3 py-2 border border-[#3A3A45] rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="Revolving Credit">Revolving Credit</option>
<option value="Term Loan">Term Loan</option>
<option value="Equipment Financing">Equipment Financing</option>
<option value="Line of Credit">Line of Credit</option>
<option value="Other">Other</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-[#8B8B9E] mb-1">Commitment Amount ($) *</label>
<input
type="number"
value={newFacilityForm.commitmentAmount}
onChange={(e) => setNewFacilityForm({ ...newFacilityForm, commitmentAmount: e.target.value })}
className="w-full px-3 py-2 border border-[#3A3A45] rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="0"
/>
</div>
<div>
<label className="block text-sm font-medium text-[#8B8B9E] mb-1">Interest Rate *</label>
<input
type="text"
value={newFacilityForm.interestRate}
onChange={(e) => setNewFacilityForm({ ...newFacilityForm, interestRate: e.target.value })}
className="w-full px-3 py-2 border border-[#3A3A45] rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="e.g., 5.5% or SOFR+200bps"
/>
</div>
<div>
<label className="block text-sm font-medium text-[#8B8B9E] mb-1">Maturity Date *</label>
<input
type="date"
value={newFacilityForm.maturityDate}
onChange={(e) => setNewFacilityForm({ ...newFacilityForm, maturityDate: e.target.value })}
className="w-full px-3 py-2 border border-[#3A3A45] rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
</div>
<div className="flex gap-3 justify-end">
<button
onClick={() => setShowNewFacility(false)}
className="px-4 py-2 text-[#8B8B9E] border border-[#3A3A45] rounded-lg hover:bg-[#111114] transition-colors font-medium"
>
Cancel
</button>
<button
onClick={handleAddFacility}
disabled={loading}
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-medium disabled:opacity-50 disabled:cursor-not-allowed"
>
{loading ? 'Saving...' : 'Save Facility'}
</button>
</div>
</div>
)}
{/* Record Draw Form */}
{showRecordDraw && (
<div className="bg-[#1A1A1F] rounded-lg border border-[#2A2A32] p-6 mb-8">
<div className="flex items-center justify-between mb-6">
<h3 className="text-lg font-semibold text-[#F0F0F3]">Record Draw</h3>
<button
onClick={() => setShowRecordDraw(false)}
className="text-[#5A5A6E] hover:text-[#8B8B9E] text-2xl font-light"
>
×
</button>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
<div>
<label className="block text-sm font-medium text-[#8B8B9E] mb-1">Facility *</label>
<select
value={newDrawForm.facilityId}
onChange={(e) => {
const facilityId = e.target.value;
const facility = facilities.find((f) => f.id === facilityId);
setNewDrawForm({
...newDrawForm,
facilityId,
interestRate: facility?.interestRate || '',
});
}}
className="w-full px-3 py-2 border border-[#3A3A45] rounded-lg focus:outline-none focus:ring-2 focus:ring-green-500"
>
<option value="">Select a facility...</option>
{facilities.map((f) => (
<option key={f.id} value={f.id}>
{f.name} - Available: {formatCurrency(f.availableAmount)}
</option>
))}
</select>
</div>
<div>
<label className="block text-sm font-medium text-[#8B8B9E] mb-1">Draw Amount ($) *</label>
<input
type="number"
value={newDrawForm.amount}
onChange={(e) => setNewDrawForm({ ...newDrawForm, amount: e.target.value })}
className="w-full px-3 py-2 border border-[#3A3A45] rounded-lg focus:outline-none focus:ring-2 focus:ring-green-500"
placeholder="0"
/>
</div>
<div>
<label className="block text-sm font-medium text-[#8B8B9E] mb-1">Draw Date *</label>
<input
type="date"
value={newDrawForm.date}
onChange={(e) => setNewDrawForm({ ...newDrawForm, date: e.target.value })}
className="w-full px-3 py-2 border border-[#3A3A45] rounded-lg focus:outline-none focus:ring-2 focus:ring-green-500"
/>
</div>
</div>
<div className="flex gap-3 justify-end">
<button
onClick={() => setShowRecordDraw(false)}
className="px-4 py-2 text-[#8B8B9E] border border-[#3A3A45] rounded-lg hover:bg-[#111114] transition-colors font-medium"
>
Cancel
</button>
<button
onClick={handleRecordDraw}
disabled={loading}
className="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors font-medium disabled:opacity-50 disabled:cursor-not-allowed"
>
{loading ? 'Recording...' : 'Record Draw'}
</button>
</div>
</div>
)}
{/* Tabs */}
<div className="bg-[#1A1A1F] rounded-lg border border-[#2A2A32] overflow-hidden">
<div className="border-b border-[#2A2A32]">
<div className="flex">
{[
{ id: 'facilities', label: 'Debt Facilities' },
{ id: 'draws', label: 'Active Draws' },
{ id: 'covenants', label: 'Covenant Compliance' },
].map((tab) => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id)}
className={`px-6 py-4 font-medium whitespace-nowrap transition-colors ${
activeTab === tab.id
? 'text-blue-600 border-b-2 border-blue-600'
: 'text-[#8B8B9E] hover:text-[#F0F0F3]'
}`}
>
{tab.label}
</button>
))}
</div>
</div>
{/* Tab Content */}
<div className="p-8">
{/* Facilities Tab */}
{activeTab === 'facilities' && (
<div>
<h2 className="text-2xl font-bold text-[#F0F0F3] mb-6">Debt Facilities</h2>
<div className="space-y-4">
{facilities.map((facility) => (
<div
key={facility.id}
className="border border-[#2A2A32] rounded-lg overflow-hidden hover:shadow-md transition-shadow"
>
<div
className="bg-[#111114] p-4 cursor-pointer hover:bg-[#1A1A1F] transition-colors"
onClick={() =>
setExpandedFacilityId(
expandedFacilityId === facility.id ? null : facility.id
)
}
>
<div className="flex items-center justify-between">
<div className="flex items-center gap-4 flex-1">
{expandedFacilityId === facility.id ? (
<ChevronUp size={20} className="text-[#5A5A6E]" />
) : (
<ChevronDown size={20} className="text-[#5A5A6E]" />
)}
<div className="flex-1">
<h3 className="text-lg font-semibold text-[#F0F0F3]">{facility.name}</h3>
<p className="text-sm text-[#8B8B9E]">{facility.lender} {facility.type}</p>
</div>
</div>
<div className="flex gap-8 text-right">
<div>
<p className="text-xs text-[#8B8B9E]">Drawn Amount</p>
<p className="text-lg font-bold text-[#F0F0F3]">
{formatCurrency(facility.drawnAmount)}
</p>
</div>
<div>
<p className="text-xs text-[#8B8B9E]">Available</p>
<p className="text-lg font-bold text-green-600">
{formatCurrency(facility.availableAmount)}
</p>
</div>
<div>
<p className="text-xs text-[#8B8B9E]">Rate</p>
<p className="text-lg font-bold text-[#F0F0F3]">{facility.interestRate}</p>
</div>
<div>
<p className="text-xs text-[#8B8B9E]">Maturity</p>
<p className="text-lg font-bold text-[#F0F0F3]">{formatDate(facility.maturityDate)}</p>
</div>
<div>
<span className="inline-block px-3 py-1 rounded-full text-xs font-semibold bg-green-900/25 text-green-800">
{facility.status}
</span>
</div>
</div>
</div>
</div>
{/* Expanded Details */}
{expandedFacilityId === facility.id && (
<div className="border-t border-[#2A2A32] p-4 bg-[#1A1A1F]">
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
<div>
<p className="text-sm font-medium text-[#8B8B9E]">Commitment Amount</p>
<p className="text-2xl font-bold text-[#F0F0F3] mt-1">
{formatCurrency(facility.commitmentAmount)}
</p>
</div>
<div>
<p className="text-sm font-medium text-[#8B8B9E]">Drawn</p>
<p className="text-2xl font-bold text-[#F0F0F3] mt-1">
{((facility.drawnAmount / facility.commitmentAmount) * 100).toFixed(1)}%
</p>
</div>
<div>
<p className="text-sm font-medium text-[#8B8B9E]">Available Capacity</p>
<p className="text-2xl font-bold text-green-600 mt-1">
{((facility.availableAmount / facility.commitmentAmount) * 100).toFixed(1)}%
</p>
</div>
</div>
{facility.draws.length > 0 && (
<div>
<h4 className="text-sm font-semibold text-[#F0F0F3] mb-3">Draws on This Facility</h4>
<div className="space-y-2">
{facility.draws.map((draw) => (
<div
key={draw.id}
className="flex items-center justify-between p-3 bg-[#111114] rounded border border-[#2A2A32]"
>
<div>
<p className="text-sm font-medium text-[#F0F0F3]">{formatDate(draw.drawDate)}</p>
<p className="text-xs text-[#8B8B9E]">{draw.interestRate}</p>
</div>
<div className="text-right">
<p className="text-sm font-bold text-[#F0F0F3]">{formatCurrency(draw.amount)}</p>
<span
className={`inline-block text-xs font-semibold px-2 py-1 rounded mt-1 ${
draw.status === 'Active'
? 'bg-blue-900/25 text-blue-800'
: draw.status === 'Repaid'
? 'bg-green-900/25 text-green-800'
: 'bg-orange-900/25 text-orange-800'
}`}
>
{draw.status}
</span>
</div>
</div>
))}
</div>
</div>
)}
</div>
)}
</div>
))}
</div>
</div>
)}
{/* Draws Tab */}
{activeTab === 'draws' && (
<div>
<h2 className="text-2xl font-bold text-[#F0F0F3] mb-6">Active Draws</h2>
{draws.length === 0 ? (
<div className="text-center py-12">
<p className="text-[#8B8B9E]">No active draws. Record your first draw using the button at the top.</p>
</div>
) : (
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-[#3A3A45] bg-[#111114]">
<th className="px-4 py-3 text-left font-semibold text-[#8B8B9E]">Facility</th>
<th className="px-4 py-3 text-left font-semibold text-[#8B8B9E]">Draw Date</th>
<th className="px-4 py-3 text-right font-semibold text-[#8B8B9E]">Amount</th>
<th className="px-4 py-3 text-left font-semibold text-[#8B8B9E]">Interest Rate</th>
<th className="px-4 py-3 text-left font-semibold text-[#8B8B9E]">Status</th>
</tr>
</thead>
<tbody className="divide-y divide-[#2A2A32]">
{draws.map((draw) => {
const facility = facilities.find((f) => f.id === draw.facilityId);
return (
<tr key={draw.id} className="hover:bg-[#111114] transition-colors">
<td className="px-4 py-3 font-medium text-[#F0F0F3]">{facility?.name}</td>
<td className="px-4 py-3 text-[#8B8B9E]">{formatDate(draw.drawDate)}</td>
<td className="px-4 py-3 text-right font-medium">{formatCurrency(draw.amount)}</td>
<td className="px-4 py-3 text-[#8B8B9E]">{draw.interestRate}</td>
<td className="px-4 py-3">
<span
className={`inline-block px-3 py-1 rounded text-xs font-semibold ${
draw.status === 'Active'
? 'bg-blue-900/25 text-blue-800'
: draw.status === 'Repaid'
? 'bg-green-900/25 text-green-800'
: 'bg-orange-900/25 text-orange-800'
}`}
>
{draw.status}
</span>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
)}
</div>
)}
{/* Covenants Tab */}
{activeTab === 'covenants' && (
<div>
<h2 className="text-2xl font-bold text-[#F0F0F3] mb-6">Covenant Compliance Dashboard</h2>
<div className="space-y-4">
{covenants.map((covenant) => (
<div
key={covenant.id}
className={`border rounded-lg p-4 hover:shadow-md transition-shadow ${getCovenanStatusColor(
covenant.status
)}`}
>
<div className="flex items-start justify-between mb-4">
<div>
<div className="flex items-center gap-2 mb-1">
{getCovenanStatusIcon(covenant.status)}
<p className="text-sm font-semibold text-[#F0F0F3]">{covenant.name}</p>
</div>
<p className="text-xs text-[#8B8B9E] mt-1">{covenant.type} Covenant</p>
</div>
<span
className={`px-3 py-1 rounded-full text-xs font-semibold flex items-center gap-1 ${getCovenanStatusColor(
covenant.status
)}`}
>
{covenant.status}
</span>
</div>
<div className="grid grid-cols-4 gap-4 text-sm">
<div>
<p className="text-[#8B8B9E] font-medium">Metric</p>
<p className="font-semibold text-[#F0F0F3] mt-1">{covenant.metric}</p>
</div>
<div>
<p className="text-[#8B8B9E] font-medium">Threshold</p>
<p className="font-semibold text-[#F0F0F3] mt-1">{covenant.threshold}</p>
</div>
<div>
<p className="text-[#8B8B9E] font-medium">Current Value</p>
<p className="font-semibold text-[#F0F0F3] mt-1">{covenant.currentValue}</p>
</div>
<div>
<p className="text-[#8B8B9E] font-medium">Headroom</p>
<p className="font-semibold text-[#F0F0F3] mt-1">{covenant.headroom}</p>
</div>
</div>
<p className="text-xs text-[#8B8B9E] mt-3">
Last checked: {formatDate(covenant.lastChecked)}
</p>
</div>
))}
</div>
</div>
)}
</div>
</div>
</div>
</div>
);
}