Skip to content

Instantly share code, notes, and snippets.

@redefinered
Created December 8, 2020 03:13
Show Gist options
  • Save redefinered/3ced93e674cffbf67b20627697327537 to your computer and use it in GitHub Desktop.
Save redefinered/3ced93e674cffbf67b20627697327537 to your computer and use it in GitHub Desktop.
/* eslint-disable react/prop-types */
import React from 'react';
// import TextField from '@material-ui/core/TextField';
import InputBase from '@material-ui/core/InputBase';
import Autocomplete from '@material-ui/lab/Autocomplete';
import LocationOnIcon from '@material-ui/icons/LocationOn';
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';
import { makeStyles } from '@material-ui/core/styles';
import parse from 'autosuggest-highlight/parse';
import throttle from 'lodash/throttle';
import { compose } from 'redux';
import { connect } from 'react-redux';
import { Creators as UserCreators } from 'modules/ducks/user/user.actions';
import { Creators as PlaceCreators } from 'modules/ducks/place/place.actions';
import { createStructuredSelector } from 'reselect';
import { selectLocation } from 'modules/ducks/place/place.selectors';
import { GoogleApiWrapper } from 'google-maps-react';
import axios from 'axios';
const { REACT_APP_API_KEY } = process.env;
const autocompleteService = { current: null };
const useStyles = makeStyles((theme) => ({
icon: {
color: theme.palette.text.secondary,
marginRight: theme.spacing(2)
},
paper: {
padding: theme.spacing(2),
margin: '30px 0 0 0',
color: theme.palette.text.secondary
}
}));
const LocationSearchBar = ({ google, setCurrentLocationAction, setLocationAction }) => {
// console.log({ userLocationAddress });
const classes = useStyles();
const [value, setValue] = React.useState(null);
const [inputValue, setInputValue] = React.useState('');
const [options, setOptions] = React.useState([]);
const [pageError, setPageError] = React.useState(null);
// eslint-disable-next-line no-unused-vars
const [pageLoading, setPageloading] = React.useState(false);
// const [userAddress, setUserAddress] = React.useState(null);
const fetch = React.useMemo(
() =>
throttle((request, callback) => {
autocompleteService.current.getPlacePredictions(request, callback);
}, 200),
[]
);
React.useEffect(() => {
let active = true;
if (!autocompleteService.current && google) {
autocompleteService.current = new google.maps.places.AutocompleteService();
}
if (!autocompleteService.current) {
return undefined;
}
if (inputValue === '') {
setOptions(value ? [value] : []);
return undefined;
}
fetch({ input: inputValue }, (results) => {
if (active) {
let newOptions = [];
if (value) {
newOptions = [value];
}
if (results) {
newOptions = [...newOptions, ...results];
}
setOptions(newOptions);
}
});
if (value) {
setLocationAction({ location: value });
}
return () => {
active = false;
};
}, [value, inputValue, fetch]);
// eslint-disable-next-line no-unused-vars
const getCurrentPosition = (event) => {
event.preventDefault();
setPageloading(true);
// eslint-disable-next-line no-undef
if ('geolocation' in navigator) {
// eslint-disable-next-line no-undef
navigator.geolocation.getCurrentPosition(
({ coords: { latitude, longitude } }) => {
const currentLocation = { latitude, longitude };
setCurrentLocationAction({ currentLocation });
getAddress(currentLocation);
},
() => {
setPageError('Error getting location');
}
);
} else {
setPageError('Not Available');
}
};
const getAddress = async ({ latitude, longitude }) => {
try {
// gets user address with reverse geocode using coordinates from navigator.geocoder
const { data } = await axios(
`https://maps.googleapis.com/maps/api/geocode/json?latlng=${latitude},${longitude}&key=${REACT_APP_API_KEY}`
);
if (data.status !== 'OK') {
setPageloading(false);
throw new Error(data.error_message);
}
// setUserAddress(data);
// set error to null if request succeeds
setPageError(null);
let newValue = Object.assign(data, { description: data.plus_code.compound_code });
setValue(newValue);
setPageloading(false);
} catch (error) {
setPageError(error.message);
}
};
React.useEffect(() => {
// WIP: needs to call getCurrentPosition
setOptions([
{
structured_formatting: {
main_text: 'Current location',
secondary_text: 'Use your current location',
main_text_matched_substrings: []
}
},
...options
]);
}, []);
console.log({ options });
return (
<React.Fragment>
<Autocomplete
style={{ width: '100%' }}
getOptionLabel={(option) => (typeof option === 'string' ? option : option.description)}
filterOptions={(x) => x}
options={options}
autoComplete
includeInputInList
filterSelectedOptions
value={value}
onChange={(event, newValue) => {
setOptions(newValue ? [newValue, ...options] : options);
setValue(newValue);
}}
onInputChange={(event, newInputValue) => {
setInputValue(newInputValue);
}}
renderInput={(params) => (
<div ref={params.InputProps.ref}>
<InputBase {...params.inputProps} className="search-input" placeholder="Tokyo, Japan" fullWidth />
</div>
)}
renderOption={(option) => {
const matches = option.structured_formatting.main_text_matched_substrings;
const parts = parse(
option.structured_formatting.main_text,
matches.map((match) => [match.offset, match.offset + match.length])
);
return (
<Grid container alignItems="center">
<Grid item>
<LocationOnIcon className={classes.icon} />
</Grid>
<Grid item xs>
{parts.map((part, index) => (
<span key={index} style={{ fontWeight: part.highlight ? 700 : 400 }}>
{part.text}
</span>
))}
<Typography variant="body2" color="textSecondary">
{option.structured_formatting.secondary_text}
</Typography>
</Grid>
</Grid>
);
}}
/>
{/* {pageLoading && <CircularProgress />}
<Typography align="left">
<Link href="#" onClick={getCurrentPosition}>
Use your current location
</Link>
</Typography> */}
{pageError && <p style={{ color: 'red' }}>{`Error: ${pageError}`}</p>}
</React.Fragment>
);
};
const actions = {
setCurrentLocationAction: UserCreators.setCurrentLocation,
setLocationAction: PlaceCreators.setLocation
};
const mapStateToProps = createStructuredSelector({ location: selectLocation });
export default compose(
GoogleApiWrapper({ apiKey: REACT_APP_API_KEY }),
connect(mapStateToProps, actions)
)(LocationSearchBar);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment