import React from 'react'; import { format, differenceInMinutes, parseISO } from 'date-fns'; import { CheckCircle2, Circle, Clock, MapPin, AlertCircle, Zap, Navigation } from 'lucide-react'; import { useTourStore } from './useTourStore.js'; const TimeVariance = ({ planned, actual }: { planned: string, actual: string | null }) => { if (!actual) return null; const diff = differenceInMinutes(parseISO(actual), parseISO(planned)); const isLate = diff > 0; return (
{isLate ? : } {isLate ? `Trễ ${diff} phút` : diff === 0 ? 'Đúng giờ' : `Sớm ${Math.abs(diff)} phút`}
); }; const calculateDistance = (lat1: number, lon1: number, lat2: number, lon2: number) => { const p = 0.017453292519943295; // Math.PI / 180 const c = Math.cos; const a = 0.5 - c((lat2 - lat1) * p) / 2 + c(lat1 * p) * c(lat2 * p) * (1 - c((lon2 - lon1) * p)) / 2; return 12742 * Math.asin(Math.sqrt(a)); // 2 * R; R = 6371 km }; const formatTravelTime = (minutes: number) => { if (minutes < 60) return `${minutes} phút`; const hours = Math.floor(minutes / 60); const mins = minutes % 60; return mins > 0 ? `${hours} giờ ${mins} phút` : `${hours} giờ`; }; export const ItineraryTimeline = () => { const { legs, optimizeRouting, userRole } = useTourStore(); const toggleComplete = async (locationId: string) => { // Gọi API PATCH /api/v1/locations/:id để cập nhật trạng thái console.log("Toggle status for location:", locationId); }; return (

Lộ trình chuyến đi

{legs.map((leg, legIdx) => { const totalDwellMinutes = leg.locations.reduce((acc: number, loc: any) => { if (loc.plannedStart && loc.plannedEnd) { return acc + differenceInMinutes(parseISO(loc.plannedEnd), parseISO(loc.plannedStart)); } return acc; }, 0); return (
{/* Leg Header */}
Chặng {leg.sequence}
{leg.totalDistance !== undefined && (
{leg.totalDistance} km
~ {formatTravelTime(Math.round((leg.totalDistance / 35) * 60))}
{totalDwellMinutes > 0 && (
Dừng: {formatTravelTime(totalDwellMinutes)}
)}
)} {['OWNER', 'MANAGER'].includes(userRole || '') && ( )}
{/* Vertical Line for the whole leg */}
{leg.locations.map((location, idx) => { const nextLocation = leg.locations[idx + 1]; const distanceToNext = nextLocation ? calculateDistance(location.latitude, location.longitude, nextLocation.latitude, nextLocation.longitude) : null; const averageSpeed = 35; // km/h (vận tốc trung bình giả định) const travelTimeMinutes = distanceToNext ? Math.round((distanceToNext / averageSpeed) * 60) : null; const dwellMinutes = (location.plannedStart && location.plannedEnd) ? differenceInMinutes(parseISO(location.plannedEnd), parseISO(location.plannedStart)) : null; return (
{/* Timeline Node */}
{/* Card Content */}

{location.name}

{location.address}
{dwellMinutes !== null && (
Thời gian dừng: {formatTravelTime(dwellMinutes)}
)}
{location.plannedStart ? format(parseISO(location.plannedStart), 'HH:mm') : '--:--'}
{location.status === 'COMPLETED' && location.actualStart && (
Thực tế: {format(parseISO(location.actualStart), 'HH:mm')}
)}
{/* Logic tính toán độ lệch thời gian */}
{distanceToNext !== null && travelTimeMinutes !== null && (
{distanceToNext.toFixed(2)} km ~ {formatTravelTime(travelTimeMinutes)}
)}
); })}
{leg.notes && (

* {leg.notes}

)}
); })}
); };