-
-
handleSearchLocation(e.target.value)}
- />
-
- {isSearching ? (
-
- ) : formData.name ? (
-
- ) : (
-
- )}
-
-
-
- {(searchResults.length > 0 || hasNoResults) && (
-
- {hasNoResults ? (
-
- Không tìm thấy địa điểm nào phù hợp...
-
- ) : (
- searchResults.map((result, idx) => (
-
- ))
- )}
-
- )}
+
setFormData({...formData, name: e.target.value})}
+ />
diff --git a/frontend/src/pages/TourDetailPage.tsx b/frontend/src/pages/TourDetailPage.tsx
index b6a709d..787f09a 100644
--- a/frontend/src/pages/TourDetailPage.tsx
+++ b/frontend/src/pages/TourDetailPage.tsx
@@ -24,6 +24,8 @@ import {
List,
Map as MapIconLucide,
MapPin,
+ Search,
+ Loader2,
Flag,
Clock,
Check,
@@ -198,6 +200,29 @@ export const TourDetailPage = ({ onBack, tourId, isPublicView = false }: { onBac
const [commentLocationName, setCommentLocationName] = useState('');
const [joinRequestActionId, setJoinRequestActionId] = useState
(null);
+ // State tìm kiếm cho chế độ Bản đồ trong Tab Lộ trình
+ const [searchQuery, setSearchQuery] = useState('');
+ const [searchResults, setSearchResults] = useState([]);
+ const [isSearching, setIsSearching] = useState(false);
+
+ const handleSearchLocation = async (query: string) => {
+ setSearchQuery(query);
+ if (query.trim().length < 2) {
+ setSearchResults([]);
+ return;
+ }
+ setIsSearching(true);
+ try {
+ const res = await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(query)}&limit=5&addressdetails=1&namedetails=1&accept-language=vi`);
+ const data = await res.json();
+ setSearchResults(data);
+ } catch (e) {
+ console.error("Lỗi tìm kiếm:", e);
+ } finally {
+ setIsSearching(false);
+ }
+ };
+
const fetchTour = useTourStore(state => state.fetchTour);
const fetchPublicTourDetails = useTourStore(state => state.fetchPublicTourDetails); // New action
@@ -803,6 +828,53 @@ export const TourDetailPage = ({ onBack, tourId, isPublicView = false }: { onBac
}} isPublicView={isPublicView} />
) : (
+ {/* Search Bar Overlay - Thanh tìm kiếm địa điểm trên bản đồ lộ trình */}
+ {!isPublicView && (
+
+
+
handleSearchLocation(e.target.value)}
+ />
+
+ {isSearching ? (
+
+ ) : searchQuery && (
+
+ )}
+
+ {/* Kết quả tìm kiếm */}
+ {searchResults.length > 0 && (
+
+ {searchResults.map((result, idx) => (
+
+ ))}
+
+ )}
+
+
+ )}