import React, { useState, useEffect, useMemo } from 'react'; import { ItineraryTimeline } from './ItineraryTimeline.js'; import { ExpenseManager } from './ExpenseManager.js'; import { useTourStore } from './useTourStore.js'; import { AddLocationModal } from './AddLocationModal.js'; import { MapContainer, TileLayer, Marker, Popup, useMapEvents, Polyline } from 'react-leaflet'; import { Map as MapIcon, Wallet, Image as ImageIcon, Calendar, Users, ChevronLeft, Settings, Quote, Plus, List, Map as MapIconLucide } from 'lucide-react'; import L from 'leaflet'; // Menu ngữ cảnh cho bản đồ const MapContextMenu = ({ onAction }: { onAction: (action: string, latlng: L.LatLng) => void }) => { const [menuPos, setMenuPos] = useState<{ x: number, y: number, latlng: L.LatLng } | null>(null); const { legs } = useTourStore(); useMapEvents({ contextmenu: (e) => { setMenuPos({ x: e.containerPoint.x, y: e.containerPoint.y, latlng: e.latlng }); }, click: () => setMenuPos(null), dragstart: () => setMenuPos(null) }); if (!menuPos) return null; return (
Thêm vào chặng
{legs.map(leg => ( ))}
); }; export const TourDetailPage = ({ onBack }: { onBack: () => void }) => { const [activeTab, setActiveTab] = useState<'plan' | 'expense' | 'photo' | 'settings'>('plan'); const [viewMode, setViewMode] = useState<'map' | 'timeline'>('timeline'); const [isAddLocationOpen, setIsAddLocationOpen] = useState(false); const { currentTour, fetchTour, fetchPublicTours, publicTours, userRole, legs } = useTourStore(); useEffect(() => { const loadData = async () => { // Nếu chưa có tour nào trong store, thử tải danh sách public trước if (publicTours.length === 0) { await fetchPublicTours(); } }; loadData(); }, []); useEffect(() => { // Lấy tour đầu tiên từ danh sách khám phá để hiển thị demo if (publicTours.length > 0 && !currentTour) { fetchTour(publicTours[0].id); } }, [publicTours, currentTour, fetchTour]); // Định nghĩa các tab dựa trên quyền hạn (RBAC) từ store const tabs = [ { id: 'plan', label: 'Lộ trình', icon: MapIcon, visible: true }, { id: 'expense', label: 'Chi phí', icon: Wallet, visible: ['OWNER', 'MANAGER', 'MEMBER'].includes(userRole || '') }, { id: 'photo', label: 'Ảnh', icon: ImageIcon, visible: true }, { id: 'settings', label: 'Cài đặt', icon: Settings, visible: ['OWNER', 'MANAGER'].includes(userRole || '') }, ].filter(t => t.visible); const hasFinanceAccess = ['OWNER', 'MANAGER', 'MEMBER'].includes(userRole || ''); const travelQuotes = [ "Đừng nghe họ nói, hãy tự mình đi xem.", "Thế giới là một cuốn sách, và ai không đi du lịch thì chỉ mới đọc được một trang.", "Hành trình ngàn dặm bắt đầu từ một bước chân.", "Đi là để trở về, nhưng với một tâm hồn mới." ]; const randomQuote = useMemo(() => travelQuotes[Math.floor(Math.random() * travelQuotes.length)], []); const tourInfo = { title: currentTour?.title || "Hành trình khám phá TP.HCM", date: currentTour?.startDate ? `${new Date(currentTour.startDate).toLocaleDateString('vi-VN')} - ${new Date(currentTour.endDate).toLocaleDateString('vi-VN')}` : "Chưa xác định ngày", membersCount: currentTour?.participants?.length || 0, budget: currentTour?.totalCost ? `${Number(currentTour.totalCost).toLocaleString()} VND` : "0 VND", coverImage: currentTour?.photos?.[0]?.imageUrl || "https://images.unsplash.com/photo-1476514525535-07fb3b4ae5f1?q=80&w=2070&auto=format&fit=crop" }; return (
{/* Top Navigation Bar */}

{tourInfo.title}

{/* Spacer */}
{/* Tour Header Info */}
Tour Cover

{tourInfo.title}

{tourInfo.date}
{tourInfo.membersCount} thành viên
{/* Member Avatars Stack */}
{currentTour?.participants?.slice(0, 5).map((p: any, i: number) => (
Avatar
))} {tourInfo.membersCount > 5 && (
+{tourInfo.membersCount - 5}
)}
{/* Financial Quick-View Widget or Quote */}
{hasFinanceAccess ? ( <>

Tổng chi tiêu hiện tại

{tourInfo.budget}

) : (

"{randomQuote}"

)}
{/* Main Content Area - Điều chỉnh max-width khi ở chế độ bản đồ */}
{/* Tab Switcher */}
{tabs.map((tab) => ( ))}
{/* Tab Panels */}
{activeTab === 'plan' && (
{/* View Mode Toggle */}
{viewMode === 'timeline' ? ( ) : (
console.log(action, latlng)} /> {/* Vẽ đường Polyline nối các điểm */} {legs.map(leg => { const positions = leg.locations.map((l: any) => [l.latitude, l.longitude]); return ; })} {legs.flatMap(l => l.locations).map((loc: any) => (
{loc.name}
{loc.type}
))}
Mẹo: Nhấn giữ (Mobile) hoặc Chuột phải để ghim địa điểm
)}
)} {activeTab === 'expense' && (
)} {activeTab === 'photo' && (
{[1, 2, 3, 4, 5, 6].map((i) => (
Tour photo
))}
)} {activeTab === 'settings' && (

Tính năng quản lý thành viên đang được cập nhật...

)}
{/* Floating Action Button (Mobile) */}
{/* Add Location Modal */} {currentTour && ( setIsAddLocationOpen(false)} tourId={currentTour.id} /> )}
); };