im-amrith/crisp
0
1"use client";2import React, { useState, useEffect } from 'react';3import { MapPin, Navigation, Loader2 } from 'lucide-react';4import { LocationData } from '../types/market';5import { getCoordinates } from '../utils/geocoding';6 7interface LocationInputProps {8 onLocationChange: (location: LocationData | null) => void;9 states: string[];10 districts: string[];11 onStateChange: (state: string) => void;12 onDistrictChange: (state: string, district: string) => void;13 markets: string[];14}15 16export const LocationInput: React.FC<LocationInputProps> = ({17 onLocationChange,18 states,19 districts,20 onStateChange,21 onDistrictChange,22 markets,23}) => {24 const [isDetecting, setIsDetecting] = useState(false);25 const [selectedState, setSelectedState] = useState('');26 const [selectedDistrict, setSelectedDistrict] = useState('');27 const [selectedMarket, setSelectedMarket] = useState('');28 const [manualAddress, setManualAddress] = useState('');29 const [locationMethod, setLocationMethod] = useState<'auto' | 'manual'>('auto');30 31 const detectLocation = async () => {32 setIsDetecting(true);33 34 try {35 if (!navigator.geolocation) {36 throw new Error('Geolocation is not supported by this browser');37 }38 39 const position = await new Promise<GeolocationPosition>((resolve, reject) => {40 navigator.geolocation.getCurrentPosition(resolve, reject, {41 enableHighAccuracy: true,42 timeout: 10000,43 maximumAge: 30000044 });45 });46 47 const { latitude, longitude } = position.coords;48 49 // Reverse geocoding using a simple approach50 // In production, you'd use Google Maps Geocoding API51 const locationData: LocationData = {52 latitude,53 longitude,54 address: `Lat: ${latitude.toFixed(4)}, Lng: ${longitude.toFixed(4)}`,55 state: selectedState || 'Unknown',56 district: selectedDistrict || 'Unknown',57 market: selectedMarket || ''58 };59 60 onLocationChange(locationData);61 } catch (error) {62 console.error('Error detecting location:', error);63 64 // Handle specific geolocation errors65 if (error instanceof GeolocationPositionError) {66 switch (error.code) {67 case GeolocationPositionError.PERMISSION_DENIED:68 alert('Location access was denied. Please enable location access in your browser settings or use manual selection below.');69 break;70 case GeolocationPositionError.POSITION_UNAVAILABLE:71 alert('Location information is unavailable. Please try again or use manual selection.');72 break;73 case GeolocationPositionError.TIMEOUT:74 alert('Location request timed out. Please try again or use manual selection.');75 break;76 default:77 alert('An error occurred while detecting your location. Please use manual selection.');78 }79 } else {80 // Handle other types of errors (like unsupported browser)81 alert('Unable to detect location. Please select manually.');82 }83 84 setLocationMethod('manual');85 } finally {86 setIsDetecting(false);87 }88 };89 90 const handleManualSelection = async () => {91 if (selectedState && selectedDistrict) {92 let coords = { latitude: 0, longitude: 0 };93 const placeName = `${selectedDistrict}, ${selectedState}`;94 95 const fetchedCoords = await getCoordinates(placeName);96 if (fetchedCoords) {97 coords = { latitude: fetchedCoords.lat, longitude: fetchedCoords.lon };98 }99 100 const locationData: LocationData = {101 ...coords,102 address: manualAddress || placeName,103 state: selectedState,104 district: selectedDistrict,105 market: selectedMarket106 };107 onLocationChange(locationData);108 }109 };110 111 const handleStateChange = (state: string) => {112 setSelectedState(state);113 setSelectedDistrict('');114 setSelectedMarket('');115 onStateChange(state);116 };117 118 const handleDistrictChange = (district: string) => {119 setSelectedDistrict(district);120 setSelectedMarket('');121 onDistrictChange(selectedState, district);122 };123 124 useEffect(() => {125 const performManualSelection = async () => {126 if (selectedState && selectedDistrict) {127 const placeName = `${selectedDistrict}, ${selectedState}`;128 const fetchedCoords = await getCoordinates(placeName);129 130 if (fetchedCoords) {131 const locationData: LocationData = {132 latitude: fetchedCoords.lat,133 longitude: fetchedCoords.lon,134 address: manualAddress || placeName,135 state: selectedState,136 district: selectedDistrict,137 market: selectedMarket,138 };139 onLocationChange(locationData);140 } else {141 // If geocoding fails, send null to clear the location142 onLocationChange(null);143 }144 } else {145 // If state or district is not selected, also clear location146 onLocationChange(null);147 }148 };149 performManualSelection();150 }, [selectedState, selectedDistrict, selectedMarket, manualAddress]);151 152 return (153 <div className="professional-card p-6 animate-slide-up">154 <h2 className="heading-secondary mb-6 flex items-center">155 <div className="p-2 bg-gradient-to-br from-blue-500 to-blue-600 rounded-xl mr-3 shadow-lg">156 <MapPin className="text-white" size={20} />157 </div>158 Your Location159 </h2>160 161 <div className="flex gap-3 mb-6">162 <button163 onClick={() => setLocationMethod('auto')}164 className={`flex-1 py-3 px-4 rounded-xl font-semibold transition-all duration-200 ${165 locationMethod === 'auto'166 ? 'btn-primary'167 : 'btn-outline'168 }`}169 >170 Auto Detect171 </button>172 <button173 onClick={() => setLocationMethod('manual')}174 className={`flex-1 py-3 px-4 rounded-xl font-semibold transition-all duration-200 ${175 locationMethod === 'manual'176 ? 'btn-primary'177 : 'btn-outline'178 }`}179 >180 Manual Selection181 </button>182 </div>183 184 {locationMethod === 'auto' ? (185 <div className="space-y-6">186 <button187 onClick={detectLocation}188 disabled={isDetecting}189 className="w-full btn-secondary flex items-center justify-center disabled:opacity-50 disabled:cursor-not-allowed disabled:transform-none"190 >191 {isDetecting ? (192 <>193 <Loader2 className="animate-spin mr-2" size={20} />194 Detecting Location...195 </>196 ) : (197 <>198 <Navigation className="mr-2" size={20} />199 Detect My Location200 </>201 )}202 </button>203 <div className="text-center p-4 bg-blue-50/50 rounded-xl border border-blue-100">204 <p className="text-sm text-blue-700 font-medium">205 ๐ We'll use your GPS location to find nearby markets206 </p>207 </div>208 </div>209 ) : (210 <div className="space-y-5">211 <div className="animate-fade-in">212 <label className="block text-sm font-semibold text-gray-900 mb-3">213 State214 </label>215 <select216 value={selectedState}217 onChange={(e) => handleStateChange(e.target.value)}218 className="select-professional"219 >220 <option value="">Select State</option>221 {states.map(state => (222 <option key={state} value={state}>{state}</option>223 ))}224 </select>225 </div>226 227 {selectedState && (228 <div className="animate-slide-up">229 <label className="block text-sm font-semibold text-gray-900 mb-3">230 District231 </label>232 <select233 value={selectedDistrict}234 onChange={(e) => handleDistrictChange(e.target.value)}235 className="select-professional"236 >237 <option value="">Select District</option>238 {districts.map(district => (239 <option key={district} value={district}>{district}</option>240 ))}241 </select>242 </div>243 )}244 245 {selectedDistrict && (246 <div className="animate-slide-up">247 <label className="block text-sm font-semibold text-gray-900 mb-3">248 Market (Optional)249 </label>250 <select251 value={selectedMarket}252 onChange={(e) => setSelectedMarket(e.target.value)}253 className="select-professional"254 >255 <option value="">All Markets in District</option>256 {markets.map(market => (257 <option key={market} value={market}>{market}</option>258 ))}259 </select>260 </div>261 )}262 263 <div className="animate-fade-in">264 <label className="block text-sm font-semibold text-gray-900 mb-3">265 Address (Optional)266 </label>267 <input268 type="text"269 value={manualAddress}270 onChange={(e) => setManualAddress(e.target.value)}271 placeholder="Enter your village/town address"272 className="input-professional"273 />274 </div>275 </div>276 )}277 </div>278 );279};280 