feat: nhấn nút toggle status full bản đồ, nhấn nút bản đồ thì giao diện cũ
This commit is contained in:
@@ -363,6 +363,7 @@ export const TourDetailPage = ({
|
|||||||
const [activeTab, setActiveTab] = useState<'plan' | 'expense' | 'photo' | 'settings'>('plan');
|
const [activeTab, setActiveTab] = useState<'plan' | 'expense' | 'photo' | 'settings'>('plan');
|
||||||
const [viewMode, setViewMode] = useState<'map' | 'timeline'>('timeline');
|
const [viewMode, setViewMode] = useState<'map' | 'timeline'>('timeline');
|
||||||
const [isAddLocationOpen, setIsAddLocationOpen] = useState(false);
|
const [isAddLocationOpen, setIsAddLocationOpen] = useState(false);
|
||||||
|
const [isMapFullscreen, setIsMapFullscreen] = useState(false);
|
||||||
const [isAddMemberOpen, setIsAddMemberOpen] = useState(false);
|
const [isAddMemberOpen, setIsAddMemberOpen] = useState(false);
|
||||||
const [isAddPhotoOpen, setIsAddPhotoOpen] = useState(false);
|
const [isAddPhotoOpen, setIsAddPhotoOpen] = useState(false);
|
||||||
const [isStartPointAction, setIsStartPointAction] = useState(false);
|
const [isStartPointAction, setIsStartPointAction] = useState(false);
|
||||||
@@ -749,9 +750,9 @@ export const TourDetailPage = ({
|
|||||||
}, [routes, selectedRouteIndex]);
|
}, [routes, selectedRouteIndex]);
|
||||||
|
|
||||||
const handleNavigateToLocation = (location: any) => {
|
const handleNavigateToLocation = (location: any) => {
|
||||||
setViewMode('map');
|
|
||||||
setMapCenter([location.latitude, location.longitude]);
|
setMapCenter([location.latitude, location.longitude]);
|
||||||
setLocateTrigger(prev => prev + 1);
|
setLocateTrigger(prev => prev + 1);
|
||||||
|
setIsMapFullscreen(true);
|
||||||
|
|
||||||
notify({
|
notify({
|
||||||
title: 'Bắt đầu chỉ đường',
|
title: 'Bắt đầu chỉ đường',
|
||||||
@@ -1393,19 +1394,10 @@ export const TourDetailPage = ({
|
|||||||
onNavigate={handleNavigateToLocation}
|
onNavigate={handleNavigateToLocation}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="fixed inset-0 z-[2000] bg-white animate-in fade-in duration-500">
|
<div className="h-[60vh] w-full rounded-3xl overflow-hidden shadow-xl border-4 border-white relative animate-in fade-in duration-500">
|
||||||
{/* Nút X để quay lại từ chế độ bản đồ toàn màn hình */}
|
|
||||||
<button
|
|
||||||
onClick={() => setViewMode('timeline')}
|
|
||||||
className="absolute top-4 left-4 z-[1002] w-11 h-11 bg-white/90 backdrop-blur-md rounded-full shadow-2xl flex items-center justify-center border border-white/20 hover:bg-white transition-all active:scale-95 group"
|
|
||||||
title="Quay lại danh sách"
|
|
||||||
>
|
|
||||||
<X className="w-6 h-6 text-gray-800 group-hover:rotate-90 transition-transform duration-300" />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
{/* Search Bar Overlay - Thanh tìm kiếm địa điểm trên bản đồ lộ trình */}
|
{/* Search Bar Overlay - Thanh tìm kiếm địa điểm trên bản đồ lộ trình */}
|
||||||
{!isPublicView && (
|
{!isPublicView && (
|
||||||
<div className="absolute top-4 right-4 z-[1001] w-48 md:w-64">
|
<div className="absolute top-3 right-3 z-[1001] w-48 md:w-64">
|
||||||
<div className="relative group">
|
<div className="relative group">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
@@ -1453,14 +1445,14 @@ export const TourDetailPage = ({
|
|||||||
|
|
||||||
{/* Overlay thông tin lộ trình đề xuất (Lộ trình thông dụng nhất) */}
|
{/* Overlay thông tin lộ trình đề xuất (Lộ trình thông dụng nhất) */}
|
||||||
{selectedRouteInfo && drivingRoute.length > 0 && (
|
{selectedRouteInfo && drivingRoute.length > 0 && (
|
||||||
<div className="absolute top-4 left-1/2 -translate-x-1/2 z-[1001] bg-white/20 backdrop-blur-lg px-6 py-2.5 rounded-full border border-white/30 flex items-center gap-4 animate-in fade-in slide-in-from-top-2 duration-500 shadow-xl">
|
<div className="absolute top-3 left-1/2 -translate-x-1/2 z-[1001] bg-white/80 backdrop-blur-md px-4 py-2 rounded-2xl shadow-xl border border-white flex items-center gap-3 animate-in fade-in slide-in-from-top-2 duration-500">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Navigation className="w-4 h-4 text-blue-600 rotate-45 fill-blue-600" />
|
<Navigation className="w-3.5 h-3.5 text-blue-600 rotate-45" />
|
||||||
<span className="text-[11px] font-black text-gray-700 uppercase tracking-widest">{selectedRouteInfo.label}</span>
|
<span className="text-[10px] font-black text-gray-400 uppercase tracking-tighter">{selectedRouteInfo.label}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-3 text-sm font-black text-blue-700 whitespace-nowrap">
|
<div className="flex items-center gap-2 text-xs font-bold text-blue-700 whitespace-nowrap">
|
||||||
<span>{selectedRouteInfo.distance} km</span>
|
<span>{selectedRouteInfo.distance} km</span>
|
||||||
<span className="text-gray-400 opacity-40">•</span>
|
<span className="text-gray-300">•</span>
|
||||||
<span>{selectedRouteInfo.duration}</span>
|
<span>{selectedRouteInfo.duration}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -2100,6 +2092,95 @@ export const TourDetailPage = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Fullscreen Map Overlay - Hiển thị khi click vào nút trạng thái/chỉ đường */}
|
||||||
|
{isMapFullscreen && (
|
||||||
|
<div className="fixed inset-0 z-[5000] bg-white animate-in fade-in slide-in-from-bottom-16 duration-500">
|
||||||
|
{/* Nút X để quay lại */}
|
||||||
|
<button
|
||||||
|
onClick={() => setIsMapFullscreen(false)}
|
||||||
|
className="absolute top-4 left-4 z-[1002] w-11 h-11 bg-white/90 backdrop-blur-md rounded-full shadow-2xl flex items-center justify-center border border-white/20 hover:bg-white transition-all active:scale-95 group"
|
||||||
|
title="Đóng bản đồ"
|
||||||
|
>
|
||||||
|
<X className="w-6 h-6 text-gray-800 group-hover:rotate-90 transition-transform duration-300" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Transparent Top Bar Label - Glassmorphism style */}
|
||||||
|
{selectedRouteInfo && drivingRoute.length > 0 && (
|
||||||
|
<div className="absolute top-4 left-1/2 -translate-x-1/2 z-[1001] bg-white/20 backdrop-blur-lg px-6 py-2.5 rounded-full border border-white/30 flex items-center gap-4 animate-in fade-in slide-in-from-top-2 duration-500 shadow-xl">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Navigation className="w-4 h-4 text-blue-600 rotate-45 fill-blue-600" />
|
||||||
|
<span className="text-[11px] font-black text-gray-700 uppercase tracking-widest">{selectedRouteInfo.label}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-3 text-sm font-black text-blue-700 whitespace-nowrap">
|
||||||
|
<span>{selectedRouteInfo.distance} km</span>
|
||||||
|
<span className="text-gray-400 opacity-40">•</span>
|
||||||
|
<span>{selectedRouteInfo.duration}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<MapContainer
|
||||||
|
center={mapCenter}
|
||||||
|
zoom={mapZoom}
|
||||||
|
className="h-full w-full"
|
||||||
|
preferCanvas={true}
|
||||||
|
>
|
||||||
|
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
|
||||||
|
<MapTourBounds locations={allLocations} />
|
||||||
|
<RecenterUser position={userLocation} trigger={locateTrigger} />
|
||||||
|
<MapRotationHandler rotation={mapRotation} />
|
||||||
|
|
||||||
|
{userLocation && (
|
||||||
|
<Marker position={userLocation} icon={mapIcons.user} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{routes.length > 0 ? (
|
||||||
|
routes.map((r, i) => (
|
||||||
|
<Polyline
|
||||||
|
key={`fs-poly-${i}`}
|
||||||
|
positions={r.geometry.coordinates.map((c: any) => [c[1], c[0]])}
|
||||||
|
color={i === selectedRouteIndex ? "#2563eb" : "#94a3b8"}
|
||||||
|
weight={i === selectedRouteIndex ? 6 : 4}
|
||||||
|
opacity={i === selectedRouteIndex ? 1 : 0.4}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
) : allLocations.length > 1 && (
|
||||||
|
<Polyline positions={allLocations.map(l => [l.latitude, l.longitude]) as any} color="#3b82f6" weight={3} dashArray="5, 10" />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{allLocations.map((loc: any, index: number) => {
|
||||||
|
const isStart = startPoint && startPoint.id === loc.id;
|
||||||
|
const isEnd = endPoint && endPoint.id === loc.id;
|
||||||
|
return (
|
||||||
|
<Marker key={`fs-marker-${loc.id}`} position={[loc.latitude, loc.longitude]} icon={isStart ? mapIcons.start : isEnd ? mapIcons.end : mapIcons.visit}>
|
||||||
|
<Popup>
|
||||||
|
<div className="font-bold">{loc.name}</div>
|
||||||
|
</Popup>
|
||||||
|
</Marker>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</MapContainer>
|
||||||
|
|
||||||
|
{/* Overlay điều khiển trên bản đồ toàn màn hình */}
|
||||||
|
<div className="absolute top-4 right-4 z-[1001] flex flex-col gap-2">
|
||||||
|
<button
|
||||||
|
onClick={() => setIsMapControlsOpen(!isMapControlsOpen)}
|
||||||
|
className="w-11 h-11 bg-white/90 backdrop-blur-md rounded-2xl shadow-xl border border-white text-blue-600 flex items-center justify-center transition-all active:scale-95"
|
||||||
|
>
|
||||||
|
{travelMode === 'driving' ? <Car className="w-5 h-5" /> : travelMode === 'bike' ? <Bike className="w-5 h-5" /> : <Footprints className="w-5 h-5" />}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{isMapControlsOpen && (
|
||||||
|
<div className="bg-white/90 backdrop-blur-md p-1.5 rounded-2xl shadow-xl border border-white flex flex-col gap-1.5 animate-in slide-in-from-top-2">
|
||||||
|
<button onClick={() => { setTravelMode('driving'); setIsMapControlsOpen(false); }} className={`w-9 h-9 flex items-center justify-center rounded-xl ${travelMode === 'driving' ? 'bg-blue-600 text-white' : 'text-gray-500'}`}><Car className="w-4 h-4" /></button>
|
||||||
|
<button onClick={() => { setTravelMode('bike'); setIsMapControlsOpen(false); }} className={`w-9 h-9 flex items-center justify-center rounded-xl ${travelMode === 'bike' ? 'bg-blue-600 text-white' : 'text-gray-500'}`}><Bike className="w-4 h-4" /></button>
|
||||||
|
<button onClick={() => { setTravelMode('foot'); setIsMapControlsOpen(false); }} className={`w-9 h-9 flex items-center justify-center rounded-xl ${travelMode === 'foot' ? 'bg-blue-600 text-white' : 'text-gray-500'}`}><Footprints className="w-4 h-4" /></button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Add Member Modal */}
|
{/* Add Member Modal */}
|
||||||
{currentTour && (
|
{currentTour && (
|
||||||
<AddMemberModal
|
<AddMemberModal
|
||||||
|
|||||||
Reference in New Issue
Block a user