incr/resources/js/pages/dashboard.tsx

172 lines
5.8 KiB
TypeScript
Raw Normal View History

2025-07-12 19:59:22 +02:00
import LedDisplay from '@/components/Display/LedDisplay';
import InlineForm from '@/components/Display/InlineForm';
import ProgressBar from '@/components/Display/ProgressBar';
import StatsBox from '@/components/Display/StatsBox';
2025-07-10 15:24:15 +02:00
import { Head } from '@inertiajs/react';
2025-07-10 18:04:58 +02:00
import { useEffect, useState } from 'react';
2025-07-10 15:24:15 +02:00
2025-07-10 18:04:58 +02:00
interface PurchaseSummary {
total_shares: number;
total_investment: number;
average_cost_per_share: number;
}
interface CurrentPrice {
current_price: number | null;
}
2025-07-10 15:24:15 +02:00
export default function Dashboard() {
2025-07-10 18:04:58 +02:00
const [purchaseData, setPurchaseData] = useState<PurchaseSummary>({
total_shares: 0,
total_investment: 0,
average_cost_per_share: 0,
});
const [priceData, setPriceData] = useState<CurrentPrice>({
current_price: null,
});
2025-07-12 19:59:22 +02:00
const [showProgressBar, setShowProgressBar] = useState(false);
const [showStatsBox, setShowStatsBox] = useState(false);
const [activeForm, setActiveForm] = useState<'purchase' | 'milestone' | null>(null);
2025-07-10 18:04:58 +02:00
const [loading, setLoading] = useState(true);
// Fetch purchase summary and current price
useEffect(() => {
const fetchData = async () => {
try {
const [purchaseResponse, priceResponse] = await Promise.all([
fetch('/purchases/summary'),
fetch('/pricing/current'),
]);
if (purchaseResponse.ok) {
const purchases = await purchaseResponse.json();
setPurchaseData(purchases);
}
if (priceResponse.ok) {
const price = await priceResponse.json();
setPriceData(price);
}
} catch (error) {
console.error('Failed to fetch data:', error);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
// Refresh data after successful purchase
const handlePurchaseSuccess = async () => {
try {
const purchaseResponse = await fetch('/purchases/summary');
if (purchaseResponse.ok) {
const purchases = await purchaseResponse.json();
setPurchaseData(purchases);
}
} catch (error) {
console.error('Failed to refresh purchase data:', error);
}
};
// Calculate portfolio stats
const currentValue = priceData.current_price
? purchaseData.total_shares * priceData.current_price
: undefined;
const profitLoss = currentValue
? currentValue - purchaseData.total_investment
: undefined;
const profitLossPercentage = profitLoss && purchaseData.total_investment > 0
? (profitLoss / purchaseData.total_investment) * 100
: undefined;
const statsData = {
totalShares: purchaseData.total_shares,
totalInvestment: purchaseData.total_investment,
averageCostPerShare: purchaseData.average_cost_per_share,
currentPrice: priceData.current_price || undefined,
currentValue,
profitLoss,
profitLossPercentage,
};
if (loading) {
return (
<>
<Head title="Dashboard" />
<div className="min-h-screen bg-black flex items-center justify-center">
<div className="text-red-500 font-mono text-lg animate-pulse">
LOADING...
2025-07-10 15:24:15 +02:00
</div>
</div>
2025-07-10 18:04:58 +02:00
</>
);
}
2025-07-12 19:59:22 +02:00
// Toggle handlers with cascading behavior
const handleLedClick = () => {
const newShowProgressBar = !showProgressBar;
setShowProgressBar(newShowProgressBar);
if (!newShowProgressBar) {
// If hiding progress bar, also hide stats box
setShowStatsBox(false);
}
};
const handleProgressClick = () => {
setShowStatsBox(!showStatsBox);
};
2025-07-10 18:04:58 +02:00
return (
<>
<Head title="VWCE Tracker" />
2025-07-12 19:59:22 +02:00
{/* Stacked Layout */}
<div className="min-h-screen bg-black flex items-center justify-center">
<div className="w-full max-w-4xl mx-4 space-y-4">
{/* Box 1: LED Number Display */}
<LedDisplay
value={purchaseData.total_shares}
onClick={handleLedClick}
/>
{/* Box 2: Progress Bar (toggleable) */}
<div style={{ display: showProgressBar ? 'block' : 'none' }}>
<ProgressBar
value={purchaseData.total_shares}
onClick={handleProgressClick}
/>
</div>
{/* Box 3: Stats Box (toggleable) */}
<div style={{ display: showStatsBox ? 'block' : 'none' }}>
<StatsBox
stats={statsData}
onAddPurchase={() => setActiveForm('purchase')}
onAddMilestone={() => setActiveForm('milestone')}
/>
</div>
{/* Box 4: Forms (only when active form is set) */}
<div style={{ display: activeForm ? 'block' : 'none' }}>
<InlineForm
type={activeForm}
onClose={() => setActiveForm(null)}
onPurchaseSuccess={handlePurchaseSuccess}
onMilestoneSuccess={() => {
console.log('Milestone added successfully');
}}
/>
</div>
</div>
2025-07-10 15:24:15 +02:00
</div>
2025-07-10 18:04:58 +02:00
</>
2025-07-10 15:24:15 +02:00
);
}