# To AI Agent: Implement Smart Date-Based Accordion Auto-Expansion and Smooth Viewport Auto-Scroll ## 1. Context & UI/UX Requirements We are enhancing the routing UX between `MemberDashboard.tsx` and `ItineraryTimeline.tsx` based on `image_cc31a4.png`. ### Functional Specifications: 1. **Date-Matching Evaluation:** When a user clicks "Chi tiết hành trình" on a tour card, calculate if the current user system local date falls inside any Stage/Leg timeline block. 2. **Auto-Expansion State:** On timeline page load, the matched Leg accordion must be expanded by default (`expandedStageId === leg.id`). 3. **Smart Auto-Scroll Layout:** The viewport must smoothly auto-scroll so that the expanded Leg's title bar lands **exactly below the sticky navigation tab bar** ("Lộ trình", "Chi phí", etc.), making it fully visible at the top of the viewport without layout clipping. --- ## 2. Technical Architecture & Layout Constraints - **The Sticky Header Challenge:** Since the top navigation tab bar uses sticky/fixed positioning, a naive `scrollIntoView({ block: 'start' })` will cause the Leg's title to crawl *underneath* the tabs, hiding it. - **The Solution:** We will inject a dynamic CSS scroll-margin-top parameter (`scroll-mt-[70px]` or matching header height) on each Leg container, and trigger a minor delayed layout effect pool using a React `setTimeout` to wait for the DOM accordion expansion reflow before pulling the scroll trigger. --- ## 3. Code Refactoring Blueprint ### Step 1: Update Navigation Payload Handler in Dashboard Component Ensure the `MemberDashboard.tsx` accurately packages the matched target identifier into the client route state bucket: ```typescript import { useNavigate } from 'react-router-dom'; const navigate = useNavigate(); const handleNavigateToItinerary = (tour: any) => { let targetLegId = null; if (tour?.legs && tour.legs.length > 0) { const today = new Date(); today.setHours(0, 0, 0, 0); for (const leg of tour.legs) { const rawStart = leg.startDate || leg.plannedStart || leg.date; const rawEnd = leg.endDate || leg.plannedEnd || leg.date; if (rawStart) { const startBound = new Date(rawStart); startBound.setHours(0, 0, 0, 0); const endBound = rawEnd ? new Date(rawEnd) : new Date(rawStart); endBound.setHours(23, 59, 59, 999); if (today >= startBound && today <= endBound) { targetLegId = leg.id; break; } } } if (!targetLegId) { targetLegId = tour.legs[0].id; // Fallback to Chặng 1 if out of tour bounds } } navigate(`/tour/${tour.id}`, { state: { defaultExpandedLegId: targetLegId, shouldScrollToTarget: true } }); }; ### Step 2: Inject Safe Identifiers and Scroll Margin inside ItineraryTimeline Locate the top-level outer container div of each Leg item inside the timeline loop (currentTour.legs.map). Assign a unique id and a scroll margin class utility: {currentTour.legs.map((leg: any, legIdx: number) => (