feat: / shows current/next trip.
This commit is contained in:
parent
3186a9d549
commit
6e6c23b6ad
4 changed files with 108 additions and 54 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
|
from datetime import date
|
||||||
from fastapi import APIRouter, Depends, HTTPException
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
from sqlalchemy.orm import Session, joinedload
|
from sqlalchemy.orm import Session, joinedload
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
@ -129,3 +129,16 @@ def reconfigure_trip(trip_id: UUID, payload: TripUpdate, db: Session = Depends(g
|
||||||
"deleted_checked_trip_item_ids": deleted_checked,
|
"deleted_checked_trip_item_ids": deleted_checked,
|
||||||
"created_trip_item_ids": created_ids,
|
"created_trip_item_ids": created_ids,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@router.get("/next-id", response_model=UUID)
|
||||||
|
def get_next_trip_id(db: Session = Depends(get_db)):
|
||||||
|
today = date.today()
|
||||||
|
trip = (
|
||||||
|
db.query(models.Trip)
|
||||||
|
.filter(models.Trip.start_date >= today)
|
||||||
|
.order_by(models.Trip.start_date.asc())
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
if not trip:
|
||||||
|
raise HTTPException(status_code=404, detail="No upcoming trip found")
|
||||||
|
return trip.id
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,27 @@
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { BrowserRouter as Router, Routes, Route, Link, Navigate, useParams } from "react-router-dom";
|
import { BrowserRouter as Router, Routes, Route, Link, Navigate, useNavigate } from "react-router-dom";
|
||||||
import { getSeed, getTrips, getTripItems, toggleTripItem } from "./api";
|
import { getSeed, getTrips, getNextTripId } from "./api";
|
||||||
import ItemsPage from "./pages/ItemsPage";
|
import ItemsPage from "./pages/ItemsPage";
|
||||||
import TripChecklist from "./pages/TripChecklist";
|
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() {
|
export default function App() {
|
||||||
const [trips, setTrips] = useState<any[]>([]);
|
const [trips, setTrips] = useState<any[]>([]);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
async function loadTrips() {
|
async function loadTrips() {
|
||||||
const data = await getTrips();
|
const data = await getTrips();
|
||||||
|
|
@ -16,12 +32,26 @@ export default function App() {
|
||||||
loadTrips();
|
loadTrips();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
async function goToCurrentTrip() {
|
||||||
|
try {
|
||||||
|
const id = await getNextTripId();
|
||||||
|
navigate(`/trips/${id}`);
|
||||||
|
} catch {
|
||||||
|
alert("Kein anstehender Trip gefunden");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Router>
|
|
||||||
<div className="p-4 max-w-2xl mx-auto">
|
<div className="p-4 max-w-2xl mx-auto">
|
||||||
<h1 className="text-2xl font-bold mb-4">Packlist</h1>
|
<h1 className="text-2xl font-bold mb-4">Packlist</h1>
|
||||||
|
|
||||||
<div className="flex gap-2 mb-4">
|
<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">
|
<Link to="/trips">
|
||||||
<button className="bg-blue-500 text-white px-4 py-2 rounded">
|
<button className="bg-blue-500 text-white px-4 py-2 rounded">
|
||||||
Alle Trips
|
Alle Trips
|
||||||
|
|
@ -66,9 +96,11 @@ export default function App() {
|
||||||
element={<TripChecklist trips={trips} />}
|
element={<TripChecklist trips={trips} />}
|
||||||
/>
|
/>
|
||||||
<Route path="/items" element={<ItemsPage />} />
|
<Route path="/items" element={<ItemsPage />} />
|
||||||
<Route path="/" element={<Navigate to="/trips" />} />
|
<Route path="/" element={<NextTripRedirect trips={trips} />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</div>
|
</div>
|
||||||
</Router>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wichtig: Der <App />-Inhalt muss innerhalb von <Router> verwendet werden!
|
||||||
|
// In main.tsx ist das bereits der Fall.
|
||||||
|
|
|
||||||
|
|
@ -82,3 +82,9 @@ export async function createItem(name: string, tags: string[]): Promise<Item> {
|
||||||
if (!res.ok) throw new Error("Failed to create item");
|
if (!res.ok) throw new Error("Failed to create item");
|
||||||
return res.json();
|
return res.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getNextTripId(): Promise<string> {
|
||||||
|
const res = await fetch(`${API_BASE}/trips/next-id`);
|
||||||
|
if (!res.ok) throw new Error("No upcoming trip found");
|
||||||
|
return res.json();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,16 @@ import React from 'react';
|
||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
import { BrowserRouter } from "react-router-dom";
|
||||||
|
|
||||||
const queryClient = new QueryClient();
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
|
<BrowserRouter>
|
||||||
<App />
|
<App />
|
||||||
|
</BrowserRouter>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
);
|
);
|
||||||
Loading…
Reference in a new issue