98 lines
2.6 KiB
React
98 lines
2.6 KiB
React
|
|
import { useState, useEffect } from 'react';
|
||
|
|
import DaySection from './DaySection';
|
||
|
|
import axios from 'axios';
|
||
|
|
|
||
|
|
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}` }
|
||
|
|
});
|
||
|
|
setCalendarSlots(response.data.data || []);
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Error fetching calendar slots:', error);
|
||
|
|
} finally {
|
||
|
|
setLoading(false);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleScheduleItem = async (plannableItemId, startDatetime, endDatetime) => {
|
||
|
|
try {
|
||
|
|
const token = localStorage.getItem('token');
|
||
|
|
await axios.post(
|
||
|
|
`${API_URL}/api/planned-items`,
|
||
|
|
{
|
||
|
|
plannable_item_id: plannableItemId,
|
||
|
|
trip_id: trip.id,
|
||
|
|
start_datetime: startDatetime,
|
||
|
|
end_datetime: endDatetime,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
headers: { Authorization: `Bearer ${token}` }
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
await fetchCalendarSlots();
|
||
|
|
if (onScheduleSuccess) {
|
||
|
|
onScheduleSuccess();
|
||
|
|
}
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Error scheduling item:', error);
|
||
|
|
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; d.setDate(d.getDate() + 1)) {
|
||
|
|
days.push(new Date(d));
|
||
|
|
}
|
||
|
|
|
||
|
|
return days;
|
||
|
|
};
|
||
|
|
|
||
|
|
const getSlotsForDay = (date) => {
|
||
|
|
const dateString = date.toISOString().split('T')[0];
|
||
|
|
return calendarSlots.filter(slot => slot.slot_date === dateString);
|
||
|
|
};
|
||
|
|
|
||
|
|
if (loading) {
|
||
|
|
return <div className="p-4 text-gray-500">Loading timeline...</div>;
|
||
|
|
}
|
||
|
|
|
||
|
|
const days = generateDays();
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="trip-timeline">
|
||
|
|
<h3 className="text-xl font-semibold mb-4">Trip Timeline</h3>
|
||
|
|
<div className="space-y-8">
|
||
|
|
{days.map((day, index) => (
|
||
|
|
<DaySection
|
||
|
|
key={day.toISOString()}
|
||
|
|
date={day}
|
||
|
|
dayNumber={index + 1}
|
||
|
|
slots={getSlotsForDay(day)}
|
||
|
|
plannableItems={plannableItems}
|
||
|
|
onScheduleItem={handleScheduleItem}
|
||
|
|
/>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
export default TripTimeline;
|