From e438d35b488f495b501c74f3d75a3cc8f2e8d24e Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Thu, 25 Dec 2025 11:14:00 +0330 Subject: [PATCH] back icon in new address --- .../(Profile)/profile/address/new/page.tsx | 124 ++++++++++++++++-- src/components/map/CustomMap.tsx | 9 ++ 2 files changed, 125 insertions(+), 8 deletions(-) diff --git a/src/app/[name]/(Profile)/profile/address/new/page.tsx b/src/app/[name]/(Profile)/profile/address/new/page.tsx index 2d57de5..e09c6fe 100644 --- a/src/app/[name]/(Profile)/profile/address/new/page.tsx +++ b/src/app/[name]/(Profile)/profile/address/new/page.tsx @@ -13,6 +13,7 @@ import { useAddressForm } from './hooks/useAddressForm'; import { fetchAddressFromCoordinates } from './utils/fetchAddress'; import { useGetAddressById } from '../hooks/useAddressData'; import { useGetAbout } from '@/app/[name]/(Main)/about/hooks/useAboutData'; +import { ActiveSearchbox } from '@/components/input/ActiveSearchbox'; const CustomMap = dynamic( () => import('@/components/map/CustomMap'), @@ -34,6 +35,10 @@ function OrderTrackingPage() { const [selectedAddress, setSelectedAddress] = useState(null); const [markers, setMarkers] = useState([]); const [initialPositionSet, setInitialPositionSet] = useState(false); + const [isSearching, setIsSearching] = useState(false); + const [searchResults, setSearchResults] = useState>([]); + const [mapInstance, setMapInstance] = useState(null); + const [isSearchOpen, setIsSearchOpen] = useState(false); const restaurant = aboutData?.data; @@ -158,6 +163,72 @@ function OrderTrackingPage() { setSelectedAddress(null); }; + const [searchTimeout, setSearchTimeout] = useState(); + + const handleSearch = async (value: string) => { + if (!value || value.trim().length === 0) { + setSearchResults([]); + setIsSearchOpen(false); + return; + } + + if (searchTimeout) { + clearTimeout(searchTimeout); + } + + setIsSearching(true); + setIsSearchOpen(true); + + const timeout = setTimeout(async () => { + try { + const viewbox = '44.0,25.0,63.0,40.0'; + const response = await fetch( + `https://nominatim.openstreetmap.org/search?` + + `format=json&` + + `q=${encodeURIComponent(value)}&` + + `countrycodes=ir&` + + `viewbox=${viewbox}&` + + `bounded=0&` + + `limit=10&` + + `namedetails=1&` + + `accept-language=fa` + , { + headers: { + 'Accept-Language': 'fa,en;q=0.9' + } + }); + interface SearchResult { + place_id: string; + display_name: string; + lat: string; + lon: string; + } + const data: SearchResult[] = await response.json(); + setSearchResults(data.map((item) => ({ + id: item.place_id, + title: item.display_name, + position: [parseFloat(item.lat), parseFloat(item.lon)] as [number, number] + }))); + } catch (error) { + console.error('Search error:', error); + setSearchResults([]); + } finally { + setIsSearching(false); + } + }, 500); + + setSearchTimeout(timeout); + }; + + const handleSearchResultSelect = (result: { id: string; title: string; position: [number, number] }) => { + setSelectedPosition(result.position); + setMapCenter(result.position); + setIsSearchOpen(false); + if (mapInstance) { + mapInstance.setView(result.position, mapInstance.getZoom()); + } + }; + if (editMode && isLoadingAddress) { return (
@@ -185,20 +256,57 @@ function OrderTrackingPage() { onPositionSelect={handlePositionSelect} onZoomChange={handleZoomChange} onClick={handleMapClick} + searchEnabled={false} + onMapReady={setMapInstance} />
-
- +
+
+ {!isSearchOpen && ( + + )} +
+
+ { + const result = searchResults.find(r => r.id === v.id && r.title === v.title); + if (result) { + handleSearchResultSelect(result); + } + }} + onFocus={() => setIsSearchOpen(true)} + className="[&_div]:h-9! [&_input]:text-xs! [&_div]:px-3! [&_input]:px-2! [&_div]:dir-rtl! [&_input]:text-right! [&_input]:dir-rtl!" + /> +
+ {isSearchOpen && (isSearching || searchResults.length > 0) && ( +
+ +
+ )} +
+
{hasServiceArea && ( -
+

محدوده سرویس‌دهی روی نقشه با رنگ آبی مشخص شده است diff --git a/src/components/map/CustomMap.tsx b/src/components/map/CustomMap.tsx index d10d363..aa65d77 100644 --- a/src/components/map/CustomMap.tsx +++ b/src/components/map/CustomMap.tsx @@ -28,6 +28,7 @@ interface CustomMapProps { onClick?: (event: L.LeafletMouseEvent) => void; searchEnabled?: boolean markerActive?: boolean + onMapReady?: (map: L.Map) => void; } // Component to handle map events and position updates @@ -114,6 +115,7 @@ const CustomMap: React.FC = ({ onClick, markerActive = true, searchEnabled = true, + onMapReady, }) => { const [selectedPosition, setSelectedPosition] = useState<[number, number] | null>(null); const [mapInstance, setMapInstance] = useState(null); @@ -136,6 +138,13 @@ const CustomMap: React.FC = ({ checkTiles(); }, [mapInstance]); + // Notify parent when map is ready + useEffect(() => { + if (mapInstance && onMapReady) { + onMapReady(mapInstance); + } + }, [mapInstance, onMapReady]); + // Initialize default icon on client side only useEffect(() => { // Dynamic import of Leaflet on the client side