106 lines
3 KiB
TypeScript
106 lines
3 KiB
TypeScript
import React, { useState, useEffect } from "react";
|
||
import { BrowserRouter as Router, Routes, Route, Link, Navigate, useNavigate } from "react-router-dom";
|
||
import { getSeed, getTrips, getNextTripId } from "./api";
|
||
import ItemsPage from "./pages/ItemsPage";
|
||
import TripChecklist from "./pages/TripChecklist";
|
||
|
||
function NextTripRedirect({ trips }: { trips: any[] }) {
|
||
const [nextTripId, setNextTripId] = React.useState<string | null>(null);
|
||
const [error, setError] = React.useState<string | null>(null);
|
||
|
||
React.useEffect(() => {
|
||
getNextTripId()
|
||
.then(setNextTripId)
|
||
.catch(() => setError("Kein anstehender Trip gefunden"));
|
||
}, []);
|
||
|
||
if (error) return <div>{error}</div>;
|
||
if (!nextTripId) return <div>Lade...</div>;
|
||
return <Navigate to={`/trips/${nextTripId}`} replace />;
|
||
}
|
||
|
||
export default function App() {
|
||
const [trips, setTrips] = useState<any[]>([]);
|
||
const navigate = useNavigate();
|
||
|
||
async function loadTrips() {
|
||
const data = await getTrips();
|
||
setTrips(data);
|
||
}
|
||
|
||
useEffect(() => {
|
||
loadTrips();
|
||
}, []);
|
||
|
||
async function goToCurrentTrip() {
|
||
try {
|
||
const id = await getNextTripId();
|
||
navigate(`/trips/${id}`);
|
||
} catch {
|
||
alert("Kein anstehender Trip gefunden");
|
||
}
|
||
}
|
||
|
||
return (
|
||
<div className="p-4 max-w-2xl mx-auto">
|
||
<h1 className="text-2xl font-bold mb-4">Packlist</h1>
|
||
|
||
<div className="flex gap-2 mb-4">
|
||
<button
|
||
className="bg-yellow-500 text-white px-4 py-2 rounded"
|
||
onClick={goToCurrentTrip}
|
||
>
|
||
Zum aktuellen Trip
|
||
</button>
|
||
<Link to="/trips">
|
||
<button className="bg-blue-500 text-white px-4 py-2 rounded">
|
||
Alle Trips
|
||
</button>
|
||
</Link>
|
||
<Link to="/items">
|
||
<button className="bg-green-500 text-white px-4 py-2 rounded">
|
||
Alle Items
|
||
</button>
|
||
</Link>
|
||
<button
|
||
className="bg-gray-300 text-gray-800 px-4 py-2 rounded"
|
||
onClick={async () => {
|
||
await getSeed();
|
||
await loadTrips();
|
||
}}
|
||
>
|
||
Seed-Daten erzeugen
|
||
</button>
|
||
</div>
|
||
|
||
<Routes>
|
||
<Route
|
||
path="/trips"
|
||
element={
|
||
<ul>
|
||
{trips.map((trip) => (
|
||
<li key={trip.id} className="mb-2">
|
||
<Link
|
||
to={`/trips/${trip.id}`}
|
||
className="text-blue-600 underline"
|
||
>
|
||
{trip.name} <span className="text-gray-500">({trip.start_date} – {trip.end_date})</span>
|
||
</Link>
|
||
</li>
|
||
))}
|
||
</ul>
|
||
}
|
||
/>
|
||
<Route
|
||
path="/trips/:id"
|
||
element={<TripChecklist trips={trips} />}
|
||
/>
|
||
<Route path="/items" element={<ItemsPage />} />
|
||
<Route path="/" element={<NextTripRedirect trips={trips} />} />
|
||
</Routes>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
// Wichtig: Der <App />-Inhalt muss innerhalb von <Router> verwendet werden!
|
||
// In main.tsx ist das bereits der Fall.
|