2025-07-12 19:59:22 +02:00
|
|
|
import LedDisplay from '@/components/Display/LedDisplay';
|
|
|
|
|
import InlineForm from '@/components/Display/InlineForm';
|
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';
|
2026-05-02 18:17:42 +02:00
|
|
|
import { useCallback, useEffect, useState } from 'react';
|
2026-08-15 14:39:40 +02:00
|
|
|
import type { Tracker } from '@/types/domain';
|
2025-07-10 15:24:15 +02:00
|
|
|
|
|
|
|
|
export default function Dashboard() {
|
2026-05-09 10:51:40 +02:00
|
|
|
const [totalShares, setTotalShares] = useState(0);
|
2026-08-15 14:39:40 +02:00
|
|
|
const [formOpen, setFormOpen] = useState(false);
|
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);
|
2026-05-02 18:33:41 +02:00
|
|
|
const [tracker, setTracker] = useState<Tracker | null>(null);
|
2025-07-10 18:04:58 +02:00
|
|
|
|
2026-08-15 14:32:03 +02:00
|
|
|
const loadData = useCallback(async () => {
|
2026-08-15 14:39:40 +02:00
|
|
|
const [entriesResponse, trackerResponse] = await Promise.all([
|
2026-08-15 14:32:03 +02:00
|
|
|
fetch('/entries/summary'),
|
|
|
|
|
fetch('/tracker'),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
if (entriesResponse.ok) {
|
|
|
|
|
const entries = await entriesResponse.json();
|
|
|
|
|
setTotalShares(entries.total_quantity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let trackerExists = false;
|
|
|
|
|
|
|
|
|
|
if (trackerResponse.ok) {
|
|
|
|
|
const { exists, tracker: trackerData } = await trackerResponse.json();
|
|
|
|
|
setTracker(trackerData ?? null);
|
|
|
|
|
trackerExists = Boolean(exists);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setNeedsOnboarding(!trackerExists);
|
|
|
|
|
}, []);
|
|
|
|
|
|
2025-07-10 18:04:58 +02:00
|
|
|
useEffect(() => {
|
|
|
|
|
const fetchData = async () => {
|
|
|
|
|
try {
|
2026-08-15 14:32:03 +02:00
|
|
|
await loadData();
|
2025-07-10 18:04:58 +02:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Failed to fetch data:', error);
|
|
|
|
|
} finally {
|
|
|
|
|
setLoading(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
fetchData();
|
2026-08-15 14:32:03 +02:00
|
|
|
}, [loadData]);
|
2025-07-10 18:04:58 +02:00
|
|
|
|
2026-08-15 14:39:40 +02:00
|
|
|
const handleEntrySuccess = async () => {
|
2025-07-10 18:04:58 +02:00
|
|
|
try {
|
2026-05-02 18:17:42 +02:00
|
|
|
const entriesResponse = await fetch('/entries/summary');
|
|
|
|
|
if (entriesResponse.ok) {
|
|
|
|
|
const entries = await entriesResponse.json();
|
2026-05-09 10:51:40 +02:00
|
|
|
setTotalShares(entries.total_quantity);
|
2025-07-10 18:04:58 +02:00
|
|
|
}
|
|
|
|
|
} catch (error) {
|
2026-05-02 18:17:42 +02:00
|
|
|
console.error('Failed to refresh entry data:', error);
|
2025-07-10 18:04:58 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2026-08-15 14:32:03 +02:00
|
|
|
const handleOnboardingComplete = loadData;
|
2025-08-01 00:56:26 +02:00
|
|
|
|
2026-05-03 00:21:15 +02:00
|
|
|
if (loading) {
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<Head title="Dashboard" />
|
|
|
|
|
<TerminalSpinner fullScreen />
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-01 00:56:26 +02:00
|
|
|
if (needsOnboarding) {
|
|
|
|
|
return (
|
|
|
|
|
<>
|
2026-08-15 14:39:40 +02:00
|
|
|
<Head title="incr - Setup" />
|
2025-08-01 00:56:26 +02:00
|
|
|
<OnboardingFlow onComplete={handleOnboardingComplete} />
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-10 18:04:58 +02:00
|
|
|
return (
|
|
|
|
|
<>
|
2026-05-01 21:03:05 +02:00
|
|
|
<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
|
2026-05-09 10:51:40 +02:00
|
|
|
value={totalShares}
|
2026-08-15 14:39:40 +02:00
|
|
|
onClick={() => setFormOpen((open) => !open)}
|
2025-07-12 19:59:22 +02:00
|
|
|
/>
|
|
|
|
|
</div>
|
2025-07-13 02:10:52 +02:00
|
|
|
|
2026-08-15 14:39:40 +02:00
|
|
|
<InlineForm
|
|
|
|
|
open={formOpen}
|
|
|
|
|
unit={tracker?.unit}
|
|
|
|
|
onClose={() => setFormOpen(false)}
|
|
|
|
|
onSuccess={handleEntrySuccess}
|
|
|
|
|
/>
|
2025-07-12 19:59:22 +02:00
|
|
|
</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
|
|
|
);
|
|
|
|
|
}
|