added search functionality
This commit is contained in:
parent
05bbbbf38b
commit
e1b43921fa
5 changed files with 100 additions and 22 deletions
|
@ -1,12 +1,22 @@
|
|||
"use client"
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Dialog, DialogContent } from '@/components/ui/dialog'
|
||||
import { DialogTrigger } from '@radix-ui/react-dialog'
|
||||
import {Dialog, DialogContent, DialogTrigger,} from "@/components/ui/dialog"
|
||||
import { FiCommand } from "react-icons/fi";
|
||||
import React from 'react'
|
||||
import React, { useState } from 'react'
|
||||
import { Command, CommandInput } from '@/components/ui/command';
|
||||
import { useGlobalContext, useGlobalContextUpdate } from '@/app/context/globalContext';
|
||||
|
||||
const Search = () => {
|
||||
const {geoList, inputValue, handleInput} = useGlobalContext();
|
||||
const {setActiveCity} = useGlobalContextUpdate();
|
||||
const [hoverIndex, setHoverIndex] = useState<number>(0);
|
||||
|
||||
const getClickedCoords = (lat: number, lon: number) => {
|
||||
setActiveCity([lat, lon]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div className=''>
|
||||
<Dialog>
|
||||
|
@ -20,9 +30,30 @@ const Search = () => {
|
|||
</DialogTrigger>
|
||||
<DialogContent className='p-0'>
|
||||
<Command className='rounded-lg border shadow-md'>
|
||||
<CommandInput placeholder='Search...'/>
|
||||
<CommandInput value={inputValue} onChangeCapture={handleInput} placeholder='Search...' />
|
||||
<ul className='px-3 pb-2'>
|
||||
<p className='p-2 text-muted-foreground text-sm'>Suggestion</p>
|
||||
{geoList?.length === 0 || (!geoList && <p>No Results</p>)}
|
||||
{geoList && geoList.map((
|
||||
item: {
|
||||
name: string;
|
||||
country: string;
|
||||
state: string;
|
||||
lat: number;
|
||||
lon: number;
|
||||
},
|
||||
index: number,
|
||||
|
||||
) => {
|
||||
const {country, state, name} = item;
|
||||
return (<li key={index} onMouseEnter={() => setHoverIndex(index)} className={`py-2 px-2 text-sm rounded-md cursor-pointer
|
||||
${hoverIndex === index ? "bg-accent" : ""}
|
||||
`} onClick={() => {
|
||||
getClickedCoords(item.lat, item.lon);
|
||||
}}>
|
||||
<p>{name}, {state} {country}</p>
|
||||
</li>);
|
||||
})}
|
||||
</ul>
|
||||
</Command>
|
||||
</DialogContent>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
"use Client"
|
||||
import axios from "axios";
|
||||
import React, { createContext, useContext, useEffect, useState } from "react"
|
||||
|
||||
import DefaultState from "../utils/DefaultState";
|
||||
import {debounce} from "lodash";
|
||||
|
||||
const GlobalContext = createContext();
|
||||
const GlobalContextUpdate = createContext();
|
||||
|
@ -12,52 +13,84 @@ export const GlobalContextProvider = ({children}) => {
|
|||
const [airPollution, setAirPollution] = useState({});
|
||||
const [dailyForecast, setDailyForecast] = useState({});
|
||||
const [uvIndex, setUvIndex] = useState({});
|
||||
const [geoList, setGeoList] = useState(DefaultState);
|
||||
const [inputValue, setInputValue] = useState("");
|
||||
const [activeCity, setActiveCity] = useState([41.8781, -87.6298]);
|
||||
|
||||
const fetchForecast = async() => {
|
||||
|
||||
const fetchForecast = async(lat, lon) => {
|
||||
try {
|
||||
const res = await axios.get("api/weather")
|
||||
const res = await axios.get(`api/weather?lat=${lat}&lon=${lon}`)
|
||||
setForecast(res.data)
|
||||
|
||||
} catch (error) {
|
||||
console.log("Error fetching forecast data:", error.message)
|
||||
}
|
||||
};
|
||||
const fetchAirPollution = async() => {
|
||||
const fetchAirPollution = async(lat, lon) => {
|
||||
try {
|
||||
const res = await axios.get("api/pollution")
|
||||
const res = await axios.get(`api/pollution?lat=${lat}&lon=${lon}`)
|
||||
setAirPollution(res.data)
|
||||
} catch (error) {
|
||||
console.log("Error fetching air pollution data:", error.message)
|
||||
}
|
||||
};
|
||||
const fetchDailyForecast = async() => {
|
||||
const fetchDailyForecast = async(lat, lon) => {
|
||||
try {
|
||||
const res = await axios.get("api/dailyForecast")
|
||||
const res = await axios.get(`api/dailyForecast?lat=${lat}&lon=${lon}`)
|
||||
setDailyForecast(res.data)
|
||||
} catch (error) {
|
||||
console.log("Error fetching air forcast data:", error.message)
|
||||
}
|
||||
};
|
||||
const fetchUVIndex = async() => {
|
||||
const fetchUVIndex = async(lat, lon) => {
|
||||
try {
|
||||
const res = await axios.get("api/uvIndex")
|
||||
const res = await axios.get(`api/uvIndex?lat=${lat}&lon=${lon}`)
|
||||
setUvIndex(res.data)
|
||||
|
||||
} catch (error) {
|
||||
console.log("Error fetching air UVI data:", error.message)
|
||||
}
|
||||
}
|
||||
};
|
||||
const fetchGeoList = async (search) => {
|
||||
try {
|
||||
const res = await axios.get(`api/geoCoordinate?search=${search}`);
|
||||
setGeoList(res.data)
|
||||
|
||||
} catch (error) {
|
||||
console.log("Error fetching data:", error.message)
|
||||
}
|
||||
};
|
||||
|
||||
const handleInput = (e) => {
|
||||
setInputValue(e.target.value);
|
||||
|
||||
if(e.target.value === ""){
|
||||
setGeoList(DefaultState);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
fetchForecast();
|
||||
fetchAirPollution();
|
||||
fetchDailyForecast();
|
||||
fetchUVIndex();
|
||||
}, []);
|
||||
const debouncedFetch = debounce((search) => {
|
||||
fetchGeoList(search);
|
||||
}, 500)
|
||||
if(inputValue){
|
||||
debouncedFetch(inputValue)
|
||||
}
|
||||
return() => debouncedFetch.cancel();
|
||||
}, [inputValue])
|
||||
|
||||
useEffect(() => {
|
||||
fetchForecast(activeCity[0], activeCity[1]);
|
||||
fetchAirPollution(activeCity[0], activeCity[1]);
|
||||
fetchDailyForecast(activeCity[0], activeCity[1]);
|
||||
fetchUVIndex(activeCity[0], activeCity[1]);
|
||||
}, [activeCity]);
|
||||
|
||||
return(
|
||||
<GlobalContext.Provider value={{forecast, airPollution, dailyForecast, uvIndex}}>
|
||||
<GlobalContextUpdate.Provider>{children}</GlobalContextUpdate.Provider>
|
||||
<GlobalContext.Provider value={{forecast, airPollution, dailyForecast, uvIndex, geoList, inputValue, handleInput,}}>
|
||||
<GlobalContextUpdate.Provider value={{setActiveCity}}>{children}</GlobalContextUpdate.Provider>
|
||||
</GlobalContext.Provider>
|
||||
)
|
||||
};
|
||||
|
|
|
@ -13,6 +13,13 @@ const DefaultState = [
|
|||
lat: 43.0722,
|
||||
lon: -89.4008,
|
||||
},
|
||||
{
|
||||
name: "Milwaukee",
|
||||
country: "US",
|
||||
state: "Wisconsin",
|
||||
lat: 43.0006,
|
||||
lon: -87.9668,
|
||||
},
|
||||
{
|
||||
name: "New York",
|
||||
country: "US",
|
||||
|
@ -29,5 +36,5 @@ const DefaultState = [
|
|||
},
|
||||
]
|
||||
|
||||
export default DefaultState
|
||||
export default DefaultState;
|
||||
|
6
weather_app/package-lock.json
generated
6
weather_app/package-lock.json
generated
|
@ -19,6 +19,7 @@
|
|||
"cmdk": "^1.0.0",
|
||||
"embla-carousel-react": "^8.0.0",
|
||||
"leaflet": "^1.9.4",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.359.0",
|
||||
"moment": "^2.30.1",
|
||||
"next": "14.1.4",
|
||||
|
@ -1737,6 +1738,11 @@
|
|||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"cmdk": "^1.0.0",
|
||||
"embla-carousel-react": "^8.0.0",
|
||||
"leaflet": "^1.9.4",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.359.0",
|
||||
"moment": "^2.30.1",
|
||||
"next": "14.1.4",
|
||||
|
|
Loading…
Add table
Reference in a new issue