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