I'm building a NextJs web app where the user can explore various stores near him. I'm using google places Api to select location from the places dropdown. Based on the location the stores are displayed. Rather typing the location I want a buttons with city name which on click will set the location of that city.
Here search bar and get current location button is present along with city button
Location.tsx
useEffect(()=>{
if(!getLocation?.formattedAddress){
setLocation(true);
setHasLoction(false);
}else{
setHasLoction(true);
}
},[])
function changeLocation(data:any){
var location=JSON.stringify(data);
console.log(data?.formattedAddress);
document.getElementById("location_id").value=data?.formattedAddress;
setLocation(data?.formattedAddress);
if(location){
setHasLoction(true);
// closeLocation();
}
var {query ,pathname} = router;
var pathname="/"+router.locale+pathname
router.push(
{
pathname,
query: query,
},
{
pathname,
query: query,
},
);
handleLocation()
}
return (
<div style={{zIndex: 1000}} className={`absolute flex flex-col w-full z-1000 inset-0 shadow-lg transform ml-0 duration-200 ease-in
${location ? ' translate-y-0 ' : '-translate-y-full' } transform border-5 bg-gray-100 h-screen lg:h-100 xl:h-110 2xl:h-110 overflow-y-hidden overflow-hidden `}>
<div className='border-red-400 flex w-full'>
<div className='flex flex-col'>
<h4 className='block lg:hidden text-sm sm:text-2xl md:text-3xl lg:text-4xl mx-4 sm:mx-16 md:mx-16 mt-8 text-magenta font-heading font-semibold'>
</h4>
<div className=''>
<p className=' lg:hidden flex mx-4 sm:mx-16 md:mx-16 mt-4 font-semibold items-center text-xs
xs+:text-sm sm:text-sm text-gray-700'>
Local stores </p>
<p className=' lg:hidden flex mx-4 sm:mx-16 md:mx-16 mt-0 font-semibold items-center text-xs
xs+:text-sm sm:text-sm text-gray-700'>
</p>
</div>
</div>
<img src='/drop-down.jpg' className='hidden lg:block md:relative object-fill md:object-contain'/>
</div>
{/* <HeaderMiddle/> */}
<div className='flex items-center justify-between mx-auto mt-20 '>
{/* <Logo className="mx-auto" /> */}
<img src="/icons/x.svg" onClick = {closeLocation}
style={{zIndex: 100}} className={`${(hasLocation)?"":"hidden"} absolute font-bold z-40 h-7 w-7 top-2 bg-gold rounded-full right-2 2xl:top-5 text-gray-400 2xl:h-8 2xl:w-8 2xl:right-7 `}/>
{/* <h2 className=' font-md text-md sm:text-lg md:text-lg lg:text-lg 2xl:text-2xl '> Get best deals in your name </h2> */}
</div>
{/* <img src='/drop-down.jpg' className='relative top-0 object-contain'/> */}
<div id='location-input' style={{zIndex: 0}}
className='absolute flex flex-col justify-center
w-full lg:w-full items-center pt-36 sm:pt-20 md:pt-4 lg:pt-0 space-y-6 ml-0 mx-3
sm:mx-16 md:ml-16 lg:ml-6 xl:ml-8 2xl:ml-10 lg:mt-80'>
<div style = {{zIndex: 1000}}
className='w-full'>
<GooglePlacesAutocomplete onChange = {changeLocation}
address =
{getLocation?.formattedAddress} />
</div>
<div style={{zIndex: 1000}} className='w-full'>
<GetCurrentLocation onChange = {changeLocation} />
</div>
</div>
<div className='-mt-10'>
<button onClick={setCityLocation}
className='p-2 border'>
New York
</button>
</div>
{/* <Dialog.Overlay className="fixed inset-0 bg-gray-900 bg-
opaname-80 w-full h-full" /> */}
</div>
google-places-autocomplete.tsx
import { Autocomplete, useJsApiLoader } from "@react-google-maps/api";
import { Libraries } from "@react-google-maps/api/dist/utils/make-load-script-url";
import { LocationInput } from "@ts-types/generated";
import React, { useState ,useEffect } from "react";
import { useTranslation } from "next-i18next";
import Loader from "@components/ui/loader/loader";
import { useLocation } from "@contexts/location/location.context";
import { useCreateLogMutation } from "@data/log/use-create-log.mutation";
import useOnClickOutside from "@utils/use-click-outside";
const libraries: Libraries = ["places"];
// data,
// data: LocationInput;
export default function GooglePlacesAutocomplete({address,
onChange
}: {
onChange: any;
address :any
}) {
const { t } = useTranslation();
const [loc,setLocation]=useState(address);
const { mutate: createLog, isLoading: loading } = useCreateLogMutation();
const { isLoaded, loadError } = useJsApiLoader({
id: "google_map_autocomplete",
googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_MAP_API_KEY!,
libraries,
});
const [autocomplete, setAutocomplete] = React.useState<any>(null);
const onLoad = React.useCallback(function callback(autocompleteInstance) {
setAutocomplete(autocompleteInstance);
}, []);
const onUnmount = React.useCallback(function callback() {
setAutocomplete(null);
}, []);
const onPlaceChanged = () => {
const place = autocomplete.getPlace();
if (!place.geometry || !place.geometry.location) {
console.log("Returned place contains no geometry");
return;
}
setLocation(place.formatted_address);
const location: any = {
lat: place.geometry.location.lat(),
lng: place.geometry.location.lng(),
formattedAddress: place.formatted_address,
};
for (const component of place.address_components) {
// @ts-ignore remove once typings fixed
const componentType = component.types[0];
switch (componentType) {
case "postal_code": {
location["zip"] = component.long_name;
break;
}
case "postal_code_suffix": {
location["zip"] = `${location?.zip}-${component.long_name}`;
break;
}
case "locality":
location["city"] = component.long_name;
break;
case "administrative_area_level_1": {
location["state"] = component.short_name;
break;
}
case "country":
location["country"] = component.long_name;
break;
}
}
if (onChange) {
onChange(location);
createLog({location:location.formattedAddress}, {
onSuccess: (data: any) => {
console.log(data)
},
onError: (error: any) => {
},
});
}
};
if (loadError) {
return <div>{t("common:text-map-cant-load")}</div>;
}
return isLoaded ? (
<Autocomplete
onLoad={onLoad}
onPlaceChanged={onPlaceChanged}
onUnmount={onUnmount}
fields={["address_components", "geometry.location", "formatted_address"]}
types={["address"]}
className="flex"
>
<input
type = "text"
defaultValue={loc}
style={{borderRadius:"5px"}}
className="p-3 pl-8 mx-8 w-full sm:px-8 sm:w-full sm:mx-auto xmd:mx-4 md:w-
full md:mx-auto
2xl:p-3 lg:p-3 lg:mx-auto lg:w-full 2xl:w-full 2xl:mx-auto font-
light
focus:border-accent focus:bg-light bg-gray-80
outline-none text-xs sm:text-sm md:text-base lg:text-lg
border-gray-300 border "
/>
</Autocomplete >
) : (
<div className="flex">
<Loader simple={true} className="w-6 h-6" />
</div>
);
}