fix: lỗi hiển thị trong itineraryTimeline

This commit is contained in:
2026-06-23 11:40:41 +07:00
parent a65be48d36
commit 6b15e7ff02
17 changed files with 625 additions and 135 deletions
+37 -17
View File
@@ -75,6 +75,14 @@ export const ItineraryTimeline = ({
const [isCommentModalOpen, setIsCommentModalOpen] = useState(false);
const [commentLocationId, setCommentLocationId] = useState('');
const [commentLocationName, setCommentLocationName] = useState('');
// State to track single expanded stage (exclusive single-expansion mode)
const [expandedStageId, setExpandedStageId] = useState<string | null>(legs.length > 0 ? legs[0]?.id : null);
const toggleStageExpanded = (legId: string) => {
// Exclusive mode: if clicking the same stage, close it. Otherwise, open only the clicked one.
setExpandedStageId(prevId => prevId === legId ? null : legId);
};
// Tối ưu hóa: Cập nhật UI ngay lập tức bằng cách can thiệp vào State của Store
const handleCommentIncrement = (locationId: string) => {
@@ -197,11 +205,14 @@ export const ItineraryTimeline = ({
useEffect(() => {
console.log("ItineraryTimeline: Legs updated", legs);
// Initialize first leg as expanded when legs change
if (legs.length > 0 && !expandedStageId) {
setExpandedStageId(legs[0].id);
}
}, [legs]);
return (
<div id="itinerary-timeline-print-zone" className="max-w-2xl mx-auto p-0 bg-gray-50 min-h-screen">
<div className="px-2 pt-4">
<div id="itinerary-timeline-print-zone" className="timeline-scroll-container itinerary-timeline-container">
{legs.length === 0 ? (
<div className="text-center py-20 bg-white rounded-3xl border-2 border-dashed border-gray-200">
<List className="w-12 h-12 text-gray-300 mx-auto mb-4" />
@@ -220,9 +231,12 @@ export const ItineraryTimeline = ({
const prevLegLastLoc = legIdx > 0 ? legs[legIdx - 1]?.locations.slice(-1)[0] : null;
return (
<div key={leg.id} className="relative mb-12 animate-in fade-in slide-in-from-bottom-4 duration-300">
{/* Leg Header */}
<div className="sticky top-[136px] z-20 bg-gray-50/90 backdrop-blur-sm flex items-center mb-6 py-2 px-2">
<section key={leg.id} className={`folder-node-wrapper ${expandedStageId === leg.id ? 'expanded' : 'collapsed'}`}>
{/* Folder header row - clickable to toggle exclusive expansion */}
<div
onClick={() => toggleStageExpanded(leg.id)}
className="folder-header-row animate-in fade-in slide-in-from-bottom-4 duration-300 hover:bg-gray-50/50 transition-colors"
>
<div className="font-black text-blue-600 text-xl truncate flex-1 flex flex-col gap-1">
<div className="flex items-center gap-2">
<span className="bg-blue-600 text-white w-8 h-8 rounded-lg flex items-center justify-center text-sm shrink-0">
@@ -245,24 +259,24 @@ export const ItineraryTimeline = ({
</div>
)}
</div>
<div className="flex items-center gap-2 ml-4">
<div className="flex items-center gap-2 ml-4" onClick={(e) => e.stopPropagation()}>
{canEdit && (
<>
<button
onClick={() => onAddLocation?.(leg.id, legIdx === 0 && leg.locations.length === 0)}
onClick={(e) => { e.stopPropagation(); onAddLocation?.(leg.id, legIdx === 0 && leg.locations.length === 0); }}
className="p-2 text-gray-400 hover:text-blue-600 hover:bg-blue-50 rounded-xl transition-all"
title="Thêm địa điểm vào chặng này"
>
<Plus className="w-4 h-4" />
</button>
<button
onClick={() => handleEditLeg(leg)}
onClick={(e) => { e.stopPropagation(); handleEditLeg(leg); }}
className="p-2 text-gray-400 hover:text-blue-600 hover:bg-blue-50 rounded-xl transition-all"
>
<Edit2 className="w-4 h-4" />
</button>
<button
onClick={() => handleDeleteLeg(leg.id)}
onClick={(e) => { e.stopPropagation(); handleDeleteLeg(leg.id); }}
className="p-2 text-gray-400 hover:text-red-600 hover:bg-red-50 rounded-xl transition-all"
>
<Trash2 className="w-4 h-4" />
@@ -298,12 +312,16 @@ export const ItineraryTimeline = ({
)} {/* Only show optimize button if canEdit */}
</div>
{/* Vertical Line for the whole leg */}
{/* Mở rộng đường kẻ xuống dưới (bottom-[-3rem]) để nối liền với chặng tiếp theo */}
<div className={`absolute left-6 top-16 ${legIdx === legs.length - 1 ? 'bottom-0' : 'bottom-[-3.5rem]'} w-0.5 bg-blue-100 -z-0`} />
{/* Scrollable content body with proper z-index layering */}
<div className="child-nodes-list-wrapper">
{/* Folder child content box - Grid accordion for exclusive expansion */}
<div className={`folder-child-content-box ${expandedStageId === leg.id ? 'expanded' : ''}`}>
<div className="child-nodes-list relative">
{/* Vertical Line for the whole leg - Dynamic height */}
<div className="absolute left-6 top-16 w-0.5 bg-blue-100 -z-0 h-full" />
<div className="ml-2">
{/* Nút thêm nhanh "Điểm xuất phát" cho Chặng 1 nếu chưa có */}
<div className="ml-2">
{/* Nút thêm nhanh "Điểm xuất phát" cho Chặng 1 nếu chưa có */}
{legIdx === 0 && !leg.locations.some((loc: any) => loc.plannedStart && new Date(loc.plannedStart).getTime() === 0) && (
<div className="relative flex group mb-6 opacity-80 hover:opacity-100 transition-opacity">
<div className="z-10 mt-1.5 mr-4">
@@ -522,8 +540,11 @@ export const ItineraryTimeline = ({
</div>
);
})}
</div>
</div>
</div> {/* End of ml-2 wrapper */}
</div> {/* End of child-nodes-list */}
</div> {/* End of folder-child-content-box */}
</div> {/* End of child-nodes-list-wrapper */}
</section>
);
})
)}
@@ -546,7 +567,6 @@ export const ItineraryTimeline = ({
</button>
</div>
)}
</div>
{/* Modal Khai báo số chặng (Popover) */}
{isLegCountModalOpen && (