incr/resources/js/pages/dashboard.tsx

207 lines
7.3 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-08-01 00:56:26 +02:00
import OnboardingFlow from '@/components/Onboarding/OnboardingFlow';
2025-08-01 01:12:21 +02:00
import TerminalSpinner from '@/components/ui/TerminalSpinner';
2025-07-10 15:24:15 +02:00
import { Head } from '@inertiajs/react';
import { useCallback, useEffect, useState } from 'react';
import type { Milestone, Tracker } from '@/types/domain';
2025-07-10 15:24:15 +02:00
interface EntrySummary {
2025-07-10 18:04:58 +02:00
total_shares: number;
}
2025-07-10 15:24:15 +02:00
export default function Dashboard() {
const [totalShares, setTotalShares] = useState(0);
2025-07-13 00:18:45 +02:00
const [milestones, setMilestones] = useState<Milestone[]>([]);
2025-07-13 01:13:36 +02:00
const [selectedMilestoneIndex, setSelectedMilestoneIndex] = useState(0);
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);
2025-08-01 00:56:26 +02:00
const [needsOnboarding, setNeedsOnboarding] = useState(false);
const [tracker, setTracker] = useState<Tracker | null>(null);
2025-07-10 18:04:58 +02:00
useEffect(() => {
const fetchData = async () => {
try {
const [entriesResponse, milestonesResponse, trackerResponse] = await Promise.all([
fetch('/entries/summary'),
2025-07-13 00:18:45 +02:00
fetch('/milestones'),
fetch('/tracker'),
2025-07-10 18:04:58 +02:00
]);
let totalQuantity = 0;
let milestonesCount = 0;
if (entriesResponse.ok) {
const entries = await entriesResponse.json();
setTotalShares(entries.total_quantity);
totalQuantity = entries.total_quantity;
2025-07-10 18:04:58 +02:00
}
2025-07-13 00:18:45 +02:00
if (milestonesResponse.ok) {
const milestonesData = await milestonesResponse.json();
setMilestones(milestonesData);
milestonesCount = milestonesData.length;
2025-07-13 00:18:45 +02:00
}
2025-08-01 00:56:26 +02:00
if (trackerResponse.ok) {
const { tracker: trackerData } = await trackerResponse.json();
setTracker(trackerData ?? null);
2025-08-01 00:56:26 +02:00
}
setNeedsOnboarding(totalQuantity === 0 || milestonesCount === 0);
2025-07-10 18:04:58 +02:00
} catch (error) {
console.error('Failed to fetch data:', error);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
const handlePurchaseSuccess = async () => {
try {
const entriesResponse = await fetch('/entries/summary');
if (entriesResponse.ok) {
const entries = await entriesResponse.json();
setTotalShares(entries.total_quantity);
2025-07-10 18:04:58 +02:00
}
} catch (error) {
console.error('Failed to refresh entry data:', error);
2025-07-10 18:04:58 +02:00
}
};
2025-07-13 00:18:45 +02:00
const handleMilestoneSuccess = async () => {
try {
const milestonesResponse = await fetch('/milestones');
if (milestonesResponse.ok) {
const milestonesData = await milestonesResponse.json();
setMilestones(milestonesData);
2025-07-13 01:13:36 +02:00
setSelectedMilestoneIndex(0);
2025-07-13 00:18:45 +02:00
}
} catch (error) {
console.error('Failed to refresh milestone data:', error);
}
};
2025-07-13 01:13:36 +02:00
const handleMilestoneSelect = (index: number) => {
setSelectedMilestoneIndex(index);
};
const handleOnboardingComplete = useCallback(async () => {
const [entriesResponse, milestonesResponse, trackerResponse] = await Promise.all([
fetch('/entries/summary'),
2025-08-01 00:56:26 +02:00
fetch('/milestones'),
fetch('/tracker'),
2025-08-01 00:56:26 +02:00
]);
let totalQuantity = 0;
let milestonesCount = 0;
if (entriesResponse.ok) {
const entries = await entriesResponse.json();
setTotalShares(entries.total_quantity);
totalQuantity = entries.total_quantity;
2025-08-01 00:56:26 +02:00
}
if (milestonesResponse.ok) {
const milestonesData = await milestonesResponse.json();
setMilestones(milestonesData);
milestonesCount = milestonesData.length;
2025-08-01 00:56:26 +02:00
}
if (trackerResponse.ok) {
const { tracker: trackerData } = await trackerResponse.json();
setTracker(trackerData ?? null);
2025-08-01 00:56:26 +02:00
}
setNeedsOnboarding(totalQuantity === 0 || milestonesCount === 0);
}, []);
2025-08-01 00:56:26 +02:00
if (loading) {
return (
<>
<Head title="Dashboard" />
<TerminalSpinner fullScreen />
</>
);
}
const handleLedClick = () => {
const newShowProgressBar = !showProgressBar;
setShowProgressBar(newShowProgressBar);
if (!newShowProgressBar) {
setShowStatsBox(false);
}
};
const handleProgressClick = () => {
setShowStatsBox(!showStatsBox);
setActiveForm(null);
};
2025-08-01 00:56:26 +02:00
if (needsOnboarding) {
return (
<>
<Head title="Asset Tracker - Setup" />
<OnboardingFlow onComplete={handleOnboardingComplete} />
</>
);
}
2025-07-10 18:04:58 +02:00
return (
<>
<Head title="incr" />
2025-07-13 02:10:52 +02:00
2025-07-13 00:03:34 +02:00
<div className="min-h-screen bg-black">
<div className="w-full max-w-4xl mx-auto px-4">
<div className="pt-32">
2025-07-13 02:10:52 +02:00
<LedDisplay
value={totalShares}
unit={tracker?.unit}
2025-07-13 00:03:34 +02:00
onClick={handleLedClick}
/>
</div>
2025-07-13 02:10:52 +02:00
<div style={{ display: showProgressBar ? 'block' : 'none' }}>
<ProgressBar
currentQuantity={totalShares}
2025-07-13 00:30:19 +02:00
milestones={milestones}
2025-07-13 01:13:36 +02:00
selectedMilestoneIndex={selectedMilestoneIndex}
2025-07-12 19:59:22 +02:00
onClick={handleProgressClick}
/>
</div>
2025-07-13 02:10:52 +02:00
<div style={{ display: showStatsBox ? 'block' : 'none' }}>
<StatsBox
stats={{ totalShares }}
unit={tracker?.unit}
2025-07-13 00:18:45 +02:00
milestones={milestones}
2025-07-13 01:13:36 +02:00
selectedMilestoneIndex={selectedMilestoneIndex}
onMilestoneSelect={handleMilestoneSelect}
2025-07-12 19:59:22 +02:00
onAddPurchase={() => setActiveForm('purchase')}
onAddMilestone={() => setActiveForm('milestone')}
/>
</div>
2025-07-13 02:10:52 +02:00
<div style={{ display: activeForm && showProgressBar && showStatsBox ? 'block' : 'none' }}>
2025-07-12 19:59:22 +02:00
<InlineForm
type={activeForm}
unit={tracker?.unit}
2025-07-12 19:59:22 +02:00
onClose={() => setActiveForm(null)}
onSuccess={(type) => {
if (type === 'purchase') handlePurchaseSuccess();
else if (type === 'milestone') handleMilestoneSuccess();
}}
2025-07-12 19:59:22 +02:00
/>
</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
);
}