CoolFace
Apppublic

im-amrith/crisp

sourceHugging Faceupdated 9mo agoView on Hugging Face
0likes
LocationInput.tsx280 linesDownload Raw Back to components
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