import React, { useState, useEffect, useMemo, useCallback } from 'react' import Map from 'react-map-gl/maplibre' import DeckGL from '@deck.gl/react' import { TileLayer } from '@deck.gl/geo-layers' import { BitmapLayer, GeoJsonLayer } from '@deck.gl/layers' import { useClimateStore } from '../../store/climateStore' // the region Bounding Box (Strict Lock) const MAHARASHTRA_BOUNDS = [ [72.5, 15.5], // Southwest coordinates (Lng, Lat) [81.0, 22.1] // Northeast coordinates (Lng, Lat) ] const INITIAL_VIEW_STATE = { longitude: 76.5, latitude: 19.3, zoom: 6.0, minZoom: 5.5, maxZoom: 12, pitch: 0, bearing: 0 } export default function ClimateMap() { const { selectedVariable } = useClimateStore() const [radarTime, setRadarTime] = useState(null) const [clickedCoord, setClickedCoord] = useState(null) const [viewState, setViewState] = useState(INITIAL_VIEW_STATE) const [searchQuery, setSearchQuery] = useState('') const [isSearching, setIsSearching] = useState(false) const handleSearch = async (e) => { e.preventDefault() if (!searchQuery.trim()) return setIsSearching(true) try { const res = await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(searchQuery + ', India')}`) const data = await res.json() if (data && data.length > 0) { setViewState({ ...viewState, longitude: parseFloat(data[0].lon), latitude: parseFloat(data[0].lat), zoom: 10, transitionDuration: 1500 }) } } catch (err) { console.error('Search failed', err) } finally { setIsSearching(false) } } const handleZoom = (delta) => { setViewState(prev => ({ ...prev, zoom: Math.min(Math.max(prev.zoom + delta, prev.minZoom), prev.maxZoom), transitionDuration: 300 })) } const resetMap = () => { setViewState({ ...INITIAL_VIEW_STATE, transitionDuration: 1000 }) } // Fetch latest RainViewer timestamp for live radar useEffect(() => { fetch('https://api.rainviewer.com/public/weather-maps.json') .then(res => res.json()) .then(data => { if (data && data.radar && data.radar.past && data.radar.past.length > 0) { const latest = data.radar.past[data.radar.past.length - 1].time setRadarTime(latest) } }) .catch(console.error) }, []) const layers = useMemo(() => { const list = [] // Inverted Mask GeoJSON Layer to hide neighboring states list.push( new GeoJsonLayer({ id: 'maharashtra-mask', data: '/data/maharashtra_mask.json', pickable: false, stroked: false, filled: true, getFillColor: [248, 250, 252, 255], // matches slate-50 background perfectly }) ) // Add RainViewer layer if rain is selected and we have a timestamp if (selectedVariable === 'rain' && radarTime) { list.push( new TileLayer({ id: 'rainviewer-radar', data: `https://tilecache.rainviewer.com/v2/radar/${radarTime}/256/{z}/{x}/{y}/2/1_1.png`, minZoom: 0, maxZoom: 7, tileSize: 256, renderSubLayers: props => { const { bbox: { west, south, east, north } } = props.tile return new BitmapLayer(props, { data: null, image: props.data, bounds: [west, south, east, north], opacity: 0.85, transparentColor: [0, 0, 0, 0] }) } }) ) } return list }, [selectedVariable, radarTime]) return (