add event editing

This commit is contained in:
Logan
2026-06-21 15:35:57 -04:00
parent fce189d8c9
commit 4dd3343026
4 changed files with 111 additions and 14 deletions
+57 -13
View File
@@ -180,12 +180,15 @@ function AddEventModal({
onClose,
onAdd,
prefill,
editEventId,
}: {
trip: TripRecord;
onClose: () => void;
onAdd: (body: object) => Promise<void>;
prefill?: Partial<TripEvent>;
editEventId?: string;
}) {
const isEdit = !!editEventId;
const availableTags = trip.available_tags ?? [];
const [title, setTitle] = useState(prefill?.title ?? "");
const [date, setDate] = useState(prefill?.date ?? trip.start_date);
@@ -224,7 +227,7 @@ function AddEventModal({
});
onClose();
} catch {
setError("Failed to add event. Check the date is within the trip range.");
setError(isEdit ? "Failed to save changes." : "Failed to add event. Check the date is within the trip range.");
} finally {
setSaving(false);
}
@@ -236,7 +239,7 @@ function AddEventModal({
onSubmit={handleSubmit}
className="bg-gray-900 border border-gray-700 rounded-xl p-6 w-full max-w-lg space-y-4 max-h-[90vh] overflow-y-auto"
>
<h2 className="text-white font-bold text-lg">Add Event</h2>
<h2 className="text-white font-bold text-lg">{isEdit ? "Edit Event" : "Add Event"}</h2>
<div>
<label className="text-xs text-gray-400 block mb-1">Title</label>
@@ -341,7 +344,7 @@ function AddEventModal({
type="submit" disabled={saving}
className="bg-indigo-600 hover:bg-indigo-500 disabled:opacity-50 text-white text-sm rounded-lg px-4 py-2"
>
{saving ? "Adding…" : "Add Event"}
{saving ? (isEdit ? "Saving…" : "Adding…") : (isEdit ? "Save Changes" : "Add Event")}
</button>
</div>
</form>
@@ -359,12 +362,14 @@ function DayTimeline({
events,
isAdmin,
onDelete,
onEdit,
driveSegments,
availableTags,
}: {
events: TripEvent[];
isAdmin: boolean;
onDelete: (id: string) => void;
onEdit: (event: TripEvent) => void;
driveSegments: { fromId: string; toId: string; text: string }[];
availableTags: string[];
}) {
@@ -472,12 +477,20 @@ function DayTimeline({
</a>
)}
{isAdmin && (
<button
onClick={() => onDelete(e.event_id)}
className="text-gray-600 hover:text-red-400 text-base leading-none opacity-0 group-hover:opacity-100 transition-opacity"
>
×
</button>
<>
<button
onClick={() => onEdit(e)}
className="text-gray-600 hover:text-indigo-400 text-xs opacity-0 group-hover:opacity-100 transition-opacity"
>
Edit
</button>
<button
onClick={() => onDelete(e.event_id)}
className="text-gray-600 hover:text-red-400 text-base leading-none opacity-0 group-hover:opacity-100 transition-opacity"
>
×
</button>
</>
)}
</div>
</div>
@@ -526,10 +539,16 @@ function DayTimeline({
</a>
)}
{isAdmin && (
<button onClick={() => onDelete(e.event_id)}
className="text-gray-600 hover:text-red-400 text-sm opacity-0 group-hover:opacity-100 transition-opacity">
×
</button>
<>
<button onClick={() => onEdit(e)}
className="text-xs text-gray-600 hover:text-indigo-400 opacity-0 group-hover:opacity-100 transition-opacity">
Edit
</button>
<button onClick={() => onDelete(e.event_id)}
className="text-gray-600 hover:text-red-400 text-sm opacity-0 group-hover:opacity-100 transition-opacity">
×
</button>
</>
)}
</div>
</div>
@@ -842,6 +861,7 @@ export default function TripDetailPage() {
const [loading, setLoading] = useState(true);
const [selectedDay, setSelectedDay] = useState<string>("");
const [showAdd, setShowAdd] = useState(false);
const [editEvent, setEditEvent] = useState<TripEvent | null>(null);
const [driveTimes, setDriveTimes] = useState<Record<string, { fromId: string; toId: string; text: string }[]>>({});
const [tagInput, setTagInput] = useState("");
@@ -901,6 +921,18 @@ export default function TripDetailPage() {
} catch (e) { console.error(e); }
}
async function handleUpdateEvent(body: object) {
if (!trip || !editEvent) return;
const updated = await c2api.updateTripEvent(trip.trip_id, editEvent.event_id, body);
setTrip((prev) => {
if (!prev) return prev;
const events = prev.events.map((e) => e.event_id === updated.event_id ? updated : e)
.sort((a, b) => a.date.localeCompare(b.date) || (a.start_time ?? "").localeCompare(b.start_time ?? ""));
return { ...prev, events };
});
setEditEvent(null);
}
async function handleAddEvent(body: object) {
if (!trip) return;
const event = await c2api.createTripEvent(trip.trip_id, body);
@@ -1079,6 +1111,7 @@ export default function TripDetailPage() {
events={dayEvents}
isAdmin={isAdmin}
onDelete={handleDeleteEvent}
onEdit={setEditEvent}
driveSegments={driveTimes[selectedDay] ?? []}
availableTags={trip.available_tags ?? []}
/>
@@ -1100,6 +1133,17 @@ export default function TripDetailPage() {
prefill={selectedDay ? { date: selectedDay } : undefined}
/>
)}
{/* Edit event modal */}
{editEvent && (
<AddEventModal
trip={trip}
onClose={() => setEditEvent(null)}
onAdd={handleUpdateEvent}
prefill={editEvent}
editEventId={editEvent.event_id}
/>
)}
</div>
);
}
+2
View File
@@ -146,6 +146,8 @@ export const c2api = {
request<{ available_tags: string[] }>(`/trips/${id}/tags`, { method: "PUT", body: JSON.stringify({ available_tags }) }),
createTripEvent: (tripId: string, body: object) =>
request<import("@/lib/types").TripEvent>(`/trips/${tripId}/events`, { method: "POST", body: JSON.stringify(body) }),
updateTripEvent: (tripId: string, eventId: string, body: object) =>
request<import("@/lib/types").TripEvent>(`/trips/${tripId}/events/${eventId}`, { method: "PATCH", body: JSON.stringify(body) }),
deleteTripEvent: (tripId: string, eventId: string) =>
request(`/trips/${tripId}/events/${eventId}`, { method: "DELETE" }),
tripChat: (tripId: string, message: string, history: { role: string; content: string }[]) =>