trip-planner/frontend/src/components/timeline/TripTimeline.jsx

113 lines
3.1 KiB
JavaScript

import { useState, useEffect } from 'react';
import DaySection from './DaySection';
import axios from 'axios';
import './TripTimeline.css';
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000';
function TripTimeline({ trip, plannableItems, onScheduleSuccess }) {
const [calendarSlots, setCalendarSlots] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchCalendarSlots();
}, [trip.id]);
const fetchCalendarSlots = async () => {
try {
const token = localStorage.getItem('token');
const response = await axios.get(`${API_URL}/api/trips/${trip.id}/calendar-slots`, {
headers: { Authorization: `Bearer ${token}` }
});
const slots = response.data.data || [];
setCalendarSlots(slots);
} catch (error) {
console.error('Error fetching calendar slots:', error);
} finally {
setLoading(false);
}
};
const handleScheduleItem = async (plannableItemId, startDatetime, endDatetime) => {
try {
const token = localStorage.getItem('token');
const payload = {
plannable_item_id: plannableItemId,
trip_id: trip.id,
start_datetime: startDatetime,
end_datetime: endDatetime,
};
const response = await axios.post(
`${API_URL}/api/planned-items`,
payload,
{
headers: { Authorization: `Bearer ${token}` }
}
);
await fetchCalendarSlots();
if (onScheduleSuccess) {
onScheduleSuccess();
}
} catch (error) {
console.error('Error scheduling item:', error);
console.error('Error response:', error.response?.data);
throw error;
}
};
const generateDays = () => {
const days = [];
const start = new Date(trip.start_date);
const end = new Date(trip.end_date);
for (let d = new Date(start); d <= end; ) {
days.push(new Date(d));
d.setDate(d.getDate() + 1);
}
return days;
};
const getSlotsForDay = (date) => {
// Format date as YYYY-MM-DD in local timezone, not UTC
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const dateString = `${year}-${month}-${day}`;
const slots = calendarSlots.filter(slot => {
// slot_date comes as "2025-12-12T00:00:00.000000Z", extract just the date part
const slotDateString = slot.slot_date.split('T')[0];
return slotDateString === dateString;
});
return slots;
};
if (loading) {
return <div className="timeline-loading">Loading timeline...</div>;
}
const days = generateDays();
return (
<div className="trip-timeline">
<h3>Trip Timeline</h3>
<div className="timeline-days-container">
{days.map((day, index) => (
<DaySection
key={`${day.getFullYear()}-${day.getMonth()}-${day.getDate()}`}
date={day}
dayNumber={index + 1}
slots={getSlotsForDay(day)}
plannableItems={plannableItems}
onScheduleItem={handleScheduleItem}
/>
))}
</div>
</div>
);
}
export default TripTimeline;