diff --git a/backend/routes/trips.py b/backend/routes/trips.py index 851b2ae..45c634a 100644 --- a/backend/routes/trips.py +++ b/backend/routes/trips.py @@ -142,3 +142,11 @@ def get_next_trip_id(db: Session = Depends(get_db)): if not trip: raise HTTPException(status_code=404, detail="No upcoming trip found") return trip.id + +@router.delete("/{trip_id}", status_code=204) +def delete_trip(trip_id: UUID, db: Session = Depends(get_db)): + trip = db.get(models.Trip, trip_id) + if not trip: + raise HTTPException(status_code=404, detail="Trip not found") + db.delete(trip) + db.commit() diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 99662a4..c449ca3 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -3,6 +3,7 @@ import { BrowserRouter as Router, Routes, Route, Link, Navigate, useNavigate } f import { getSeed, getTrips, getNextTripId } from "./api"; import ItemsPage from "./pages/ItemsPage"; import TripChecklist from "./pages/TripChecklist"; +import TripsPage from "./pages/TripsPage"; function NextTripRedirect({ trips }: { trips: any[] }) { const [nextTripId, setNextTripId] = React.useState(null); @@ -74,27 +75,8 @@ export default function App() { - - {trips.map((trip) => ( -
  • - - {trip.name} ({trip.start_date} – {trip.end_date}) - -
  • - ))} - - } - /> - } - /> + } /> + } /> } /> } />
    diff --git a/frontend/src/api.ts b/frontend/src/api.ts index 6f744b6..3da39ee 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -88,3 +88,24 @@ export async function getNextTripId(): Promise { if (!res.ok) throw new Error("No upcoming trip found"); return res.json(); } + +export async function deleteTrip(tripId: string): Promise { + const res = await fetch(`${API_BASE}/trips/${tripId}`, { method: "DELETE" }); + if (!res.ok) throw new Error("Failed to delete trip"); +} + +export async function createTrip(data: { + name: string; + start_date: string; + end_date: string; + selected_tag_ids?: string[]; + marked_tag_ids?: string[]; +}): Promise { + const res = await fetch(`${API_BASE}/trips/`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(data), + }); + if (!res.ok) throw new Error("Failed to create trip"); + return res.json(); +} diff --git a/frontend/src/pages/TripsPage.tsx b/frontend/src/pages/TripsPage.tsx index ee107e8..f4e760b 100644 --- a/frontend/src/pages/TripsPage.tsx +++ b/frontend/src/pages/TripsPage.tsx @@ -1,18 +1,40 @@ import React, { useState, useEffect } from "react"; -import { getSeed, getTrips, getTripItems, toggleTripItem } from "../api"; +import { Link } from "react-router-dom"; +import { getSeed, getTrips, deleteTrip, createTrip } from "../api"; -export function TripsPage() { +export default function TripsPage() { const [trips, setTrips] = useState([]); - const [items, setItems] = useState>({}); + const [newTrip, setNewTrip] = useState({ name: "", start_date: "", end_date: "" }); + const [creating, setCreating] = useState(false); async function loadTrips() { const data = await getTrips(); setTrips(data); } - async function loadItems(tripId: string) { - const data = await getTripItems(tripId); - setItems(prev => ({ ...prev, [tripId]: data })); + async function handleDeleteTrip(tripId: string) { + if (window.confirm("Diesen Trip wirklich löschen?")) { + await deleteTrip(tripId); + await loadTrips(); + } + } + + async function handleCreateTrip(e: React.FormEvent) { + e.preventDefault(); + setCreating(true); + try { + await createTrip({ + name: newTrip.name, + start_date: newTrip.start_date, + end_date: newTrip.end_date, + selected_tag_ids: [], + marked_tag_ids: [], + }); + setNewTrip({ name: "", start_date: "", end_date: "" }); + await loadTrips(); + } finally { + setCreating(false); + } } useEffect(() => { @@ -22,15 +44,37 @@ export function TripsPage() { return (

    Packlist

    - +
    + setNewTrip(t => ({ ...t, name: e.target.value }))} + className="border rounded px-2 py-1" + required + /> + setNewTrip(t => ({ ...t, start_date: e.target.value }))} + className="border rounded px-2 py-1" + required + /> + setNewTrip(t => ({ ...t, end_date: e.target.value }))} + className="border rounded px-2 py-1" + required + /> + +
    {trips.map(trip => (
    @@ -41,31 +85,21 @@ export function TripsPage() { {trip.start_date} – {trip.end_date}

    - +
    + + Packliste anzeigen + + +
    - - {items[trip.id] && ( -
      - {items[trip.id].map(item => ( -
    • - { - await toggleTripItem(item.id); - await loadItems(trip.id); - }} - /> - {item.name_calculated} -
    • - ))} -
    - )} ))}