feat: enhance TripsPage to include tag selection and marking for new trips
This commit is contained in:
parent
c966009ab5
commit
7e1bb2f77b
1 changed files with 110 additions and 38 deletions
|
|
@ -1,17 +1,26 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { getSeed, getTrips, deleteTrip, createTrip } from "../api";
|
||||
import { getSeed, getTrips, deleteTrip, createTrip, getTags } from "../api";
|
||||
|
||||
export default function TripsPage() {
|
||||
const [trips, setTrips] = useState<any[]>([]);
|
||||
const [allTags, setAllTags] = useState<any[]>([]);
|
||||
const [newTrip, setNewTrip] = useState({ name: "", start_date: "", end_date: "" });
|
||||
const [selectedTags, setSelectedTags] = useState<string[]>([]);
|
||||
const [markedTags, setMarkedTags] = useState<string[]>([]);
|
||||
const [creating, setCreating] = useState(false);
|
||||
const [showForm, setShowForm] = useState(false);
|
||||
|
||||
async function loadTrips() {
|
||||
const data = await getTrips();
|
||||
setTrips(data);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadTrips();
|
||||
getTags().then(setAllTags);
|
||||
}, []);
|
||||
|
||||
async function handleDeleteTrip(tripId: string) {
|
||||
if (window.confirm("Diesen Trip wirklich löschen?")) {
|
||||
await deleteTrip(tripId);
|
||||
|
|
@ -27,20 +36,19 @@ export default function TripsPage() {
|
|||
name: newTrip.name,
|
||||
start_date: newTrip.start_date,
|
||||
end_date: newTrip.end_date,
|
||||
selected_tag_ids: [],
|
||||
marked_tag_ids: [],
|
||||
selected_tag_ids: selectedTags,
|
||||
marked_tag_ids: markedTags,
|
||||
});
|
||||
setNewTrip({ name: "", start_date: "", end_date: "" });
|
||||
setSelectedTags([]);
|
||||
setMarkedTags([]);
|
||||
setShowForm(false);
|
||||
await loadTrips();
|
||||
} finally {
|
||||
setCreating(false);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadTrips();
|
||||
}, []);
|
||||
|
||||
// Markiere nächsten anstehenden Trip
|
||||
const today = new Date().toISOString().slice(0, 10);
|
||||
const nextTripIdx = trips.findIndex(
|
||||
|
|
@ -48,10 +56,32 @@ export default function TripsPage() {
|
|||
);
|
||||
const nextTripId = nextTripIdx !== -1 ? trips[nextTripIdx].id : null;
|
||||
|
||||
function toggleTag(tagId: string) {
|
||||
setSelectedTags((prev) =>
|
||||
prev.includes(tagId) ? prev.filter((id) => id !== tagId) : [...prev, tagId]
|
||||
);
|
||||
// Wenn ein Tag abgewählt wird, auch aus markedTags entfernen
|
||||
setMarkedTags((prev) => prev.filter((id) => id !== tagId));
|
||||
}
|
||||
|
||||
function toggleMarkTag(tagId: string) {
|
||||
if (!selectedTags.includes(tagId)) return;
|
||||
setMarkedTags((prev) =>
|
||||
prev.includes(tagId) ? prev.filter((id) => id !== tagId) : [...prev, tagId]
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold mb-4">Packlist</h1>
|
||||
<form className="mb-4 flex gap-2 flex-wrap items-end" onSubmit={handleCreateTrip}>
|
||||
<button
|
||||
className="mb-4 bg-blue-500 text-white px-4 py-2 rounded"
|
||||
onClick={() => setShowForm((v) => !v)}
|
||||
>
|
||||
{showForm ? "Abbrechen" : "Neuen Trip anlegen"}
|
||||
</button>
|
||||
{showForm && (
|
||||
<form className="mb-4 flex flex-col gap-2 p-4 border rounded bg-gray-50" onSubmit={handleCreateTrip}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Trip-Name"
|
||||
|
|
@ -60,6 +90,7 @@ export default function TripsPage() {
|
|||
className="border rounded px-2 py-1"
|
||||
required
|
||||
/>
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
type="date"
|
||||
value={newTrip.start_date}
|
||||
|
|
@ -74,14 +105,55 @@ export default function TripsPage() {
|
|||
className="border rounded px-2 py-1"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div className="mb-1 font-semibold">Tags auswählen:</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{allTags.map((tag: any) => {
|
||||
const isSelected = selectedTags.includes(tag.id);
|
||||
const isMarked = markedTags.includes(tag.id);
|
||||
return (
|
||||
<span
|
||||
key={tag.id}
|
||||
className={
|
||||
"px-2 py-0.5 rounded cursor-pointer select-none transition " +
|
||||
(isSelected
|
||||
? isMarked
|
||||
? "bg-yellow-200 text-yellow-900 font-bold border border-yellow-400"
|
||||
: "bg-blue-100 text-blue-800 border border-blue-300"
|
||||
: "bg-gray-100 text-gray-500 border border-gray-200")
|
||||
}
|
||||
onClick={() => toggleTag(tag.id)}
|
||||
onDoubleClick={() => toggleMarkTag(tag.id)}
|
||||
title={
|
||||
isSelected
|
||||
? isMarked
|
||||
? "Doppelklick: Markierung entfernen"
|
||||
: "Doppelklick: Tag markieren"
|
||||
: "Klick: Tag auswählen"
|
||||
}
|
||||
>
|
||||
#{tag.name}
|
||||
{isMarked && isSelected && (
|
||||
<span className="ml-1 text-xs">★</span>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="text-xs text-gray-500 mt-1">
|
||||
Klick: auswählen/abwählen, Doppelklick: markieren
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
className="bg-green-500 text-white px-4 py-2 rounded"
|
||||
className="bg-green-500 text-white px-4 py-2 rounded mt-2"
|
||||
disabled={creating}
|
||||
>
|
||||
{creating ? "Anlegen..." : "Neuen Trip anlegen"}
|
||||
{creating ? "Anlegen..." : "Trip anlegen"}
|
||||
</button>
|
||||
</form>
|
||||
)}
|
||||
|
||||
{trips.map(trip => {
|
||||
const isPast = trip.start_date < today;
|
||||
|
|
|
|||
Loading…
Reference in a new issue