Skip to content

Commit

Permalink
Merge pull request #765 from hackforla/bounds-search
Browse files Browse the repository at this point in the history
Bounds Search
  • Loading branch information
bbovenzi authored Oct 31, 2020
2 parents b9eb880 + bcc2f0d commit 4fe2a24
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 188 deletions.
22 changes: 18 additions & 4 deletions app/services/stakeholder-best-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ record has been approved, it will be the most recent version (i.e., have
If you make changes to the database structure, be sure to update these
methods as well as the corresponding methods in the stakeholder-service.js.
You can search by max/min lat, lng bounds or by a center and radius(distance),
with bounds taking precedence.
*/

const booleanEitherClause = (columnName, value) => {
Expand All @@ -27,13 +30,16 @@ const search = async ({
latitude,
longitude,
distance,
maxLat,
maxLng,
minLat,
minLng,
isInactive,
verificationStatusId,
tenantId,
}) => {
const locationClause = buildLocationClause(latitude, longitude);
const categoryClause = buildCTEClause(categoryIds, "");

const sql = `${categoryClause}
select s.id, s.name, s.address_1, s.address_2, s.city, s.state, s.zip,
s.phone, s.latitude, s.longitude, s.website, s.notes,
Expand Down Expand Up @@ -69,9 +75,11 @@ const search = async ({
${buildLoginSelectsClause()}
from stakeholder_set as s
${buildLoginJoinsClause()}
where s.tenant_id = ${tenantId}
where s.tenant_id = ${tenantId}
${
Number(distance) && locationClause
maxLat && maxLng && minLat && minLng
? buildBounds({ maxLat, maxLng, minLat, minLng })
: Number(distance) && locationClause
? `AND ${locationClause} < ${distance}`
: ""
}
Expand All @@ -83,7 +91,6 @@ const search = async ({
}
order by distance
`;
// console.log(sql);
let stakeholders = [];
let categoriesResults = [];
var stakeholderResult, stakeholder_ids;
Expand Down Expand Up @@ -349,6 +356,13 @@ const buildLocationClause = (latitude, longitude) => {
return locationClause;
};

const buildBounds = ({ maxLat, maxLng, minLat, minLng }) => {
return `
AND s.latitude BETWEEN ${minLat} AND ${maxLat}
AND s.longitude BETWEEN ${minLng} AND ${maxLng}
`;
};

const buildLoginJoinsClause = () => {
return `
left join login L1 on s.created_login_id = L1.id
Expand Down
13 changes: 7 additions & 6 deletions client/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { makeStyles, ThemeProvider } from "@material-ui/core/styles";
import { Grid } from "@material-ui/core";
import theme from "theme/materialUI";
import { logout } from "services/account-service";
import { tenantId, originCoordinates } from "helpers/Configuration";
import { tenantId, defaultCoordinates } from "helpers/Configuration";

// Components
import { UserContext } from "components/user-context";
Expand Down Expand Up @@ -75,8 +75,8 @@ function App() {
const [toast, setToast] = useState({ message: "" });
const [bgImg, setBgImg] = useState("");
const [origin, setOrigin] = useState({
latitude: originCoordinates.lat,
longitude: originCoordinates.lon,
latitude: defaultCoordinates.lat,
longitude: defaultCoordinates.lon,
});

useEffect(() => {
Expand Down Expand Up @@ -127,8 +127,8 @@ function App() {
(error) => {
console.log(`Getting browser location failed: ${error.message}`);
const userCoordinates = {
latitude: originCoordinates.lat,
longitude: originCoordinates.lon,
latitude: defaultCoordinates.lat,
longitude: defaultCoordinates.lon,
};
setUserCoordinates(userCoordinates);
}
Expand Down Expand Up @@ -176,7 +176,8 @@ function App() {
<Route path="/organizations">
<Results
userCoordinates={userCoordinates}
userSearch={origin}
origin={origin}
setOrigin={setOrigin}
setToast={setToast}
/>
</Route>
Expand Down
137 changes: 30 additions & 107 deletions client/src/components/Results/ResultsContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Grid } from "@material-ui/core";
import { useOrganizationBests } from "hooks/useOrganizationBests";
import useCategoryIds from "hooks/useCategoryIds";
import { isMobile } from "helpers";
import { originCoordinates } from "helpers/Configuration";
import { defaultCoordinates } from "helpers/Configuration";
import { DEFAULT_CATEGORIES } from "constants/stakeholder";

import Filters from "./ResultsFilters";
Expand All @@ -25,11 +25,11 @@ const useStyles = makeStyles((theme) => ({

export default function ResultsContainer({
userCoordinates,
userSearch,
origin,
setOrigin,
setToast,
}) {
// Component state
const storage = window.sessionStorage;
const { data, search } = useOrganizationBests();
const [sortedData, setSortedData] = useState([]);
const classes = useStyles();
Expand All @@ -38,77 +38,34 @@ export default function ResultsContainer({
const [isMapView, setIsMapView] = useState(true);
const mobileView = isMobile();

const doSelectStakeholder = useCallback((stakeholder) => {
if (stakeholder && !mobileView) {
setViewport({
...viewport,
latitude: stakeholder.latitude,
longitude: stakeholder.longitude,
});
}
onSelectStakeholder(stakeholder);
const { categoryIds, toggleCategory } = useCategoryIds([]);
const [isVerifiedSelected, selectVerified] = useState(false);
const [viewport, setViewport] = useState({
zoom: defaultCoordinates.zoom,
latitude: origin.latitude,
longitude: origin.longitude,
logoPosition: "top-left",
});

const doSelectStakeholder = useCallback(
(stakeholder) => {
if (stakeholder && !isMobile) {
setViewport({
...viewport,
latitude: stakeholder.latitude,
longitude: stakeholder.longitude,
});
}
onSelectStakeholder(stakeholder);
},
[viewport, setViewport]
);

const switchResultsView = () => {
doSelectStakeholder();
setIsMapView(!isMapView);
};

const initialCategories = storage.categoryIds
? JSON.parse(storage.categoryIds)
: [];
const { categoryIds, toggleCategory } = useCategoryIds(initialCategories);

const initialCoords = {
locationName: userSearch
? userSearch.locationName
: storage.origin
? JSON.parse(storage.origin).locationName
: "",
latitude: userSearch
? userSearch.latitude
: storage.origin
? JSON.parse(storage.origin).latitude
: userCoordinates
? userCoordinates.latitude
: originCoordinates.lat,
longitude: userSearch
? userSearch.longitude
: storage.origin
? JSON.parse(storage.origin).longitude
: userCoordinates
? userCoordinates.longitude
: originCoordinates.lon,
};

const [radius, setRadius] = useState(
storage?.radius ? JSON.parse(storage.radius) : 5
);
const [origin, setOrigin] = useState(initialCoords);
const [isVerifiedSelected, selectVerified] = useState(
storage?.verified ? JSON.parse(storage.verified) : false
);

const viewPortHash = {
0: 4,
1: 13.5,
2: 12.5,
3: 12,
5: 11,
10: 10,
20: 9,
50: 8,
100: 7,
500: 4.5,
};

const [viewport, setViewport] = useState({
zoom: viewPortHash[radius || 0],
latitude: origin.latitude || JSON.parse(storage.origin).latitude,
longitude: origin.longitude || JSON.parse(storage.origin).longitude,
logoPosition: "top-left",
});

// Component effects

useEffect(() => {
Expand All @@ -135,74 +92,46 @@ export default function ResultsContainer({
setSortedData(data.sort(sortOrganizations));
}, [data]);

useEffect(() => {
return () => {
sessionStorage.clear();
};
}, []);

const handleSearch = useCallback(
(e, center) => {
(e, center, bounds) => {
if (e) e.preventDefault();
search({
latitude:
(center && center.lat) ||
origin.latitude ||
userCoordinates.latitude ||
JSON.parse(storage.origin).latitude,
(center && center.lat) || origin.latitude || userCoordinates.latitude,
longitude:
(center && center.lng) ||
origin.longitude ||
userCoordinates.longitude ||
JSON.parse(storage.origin).longitude,
radius,
userCoordinates.longitude,
categoryIds: categoryIds.length ? categoryIds : DEFAULT_CATEGORIES,
isInactive: "either",
verificationStatusId: 0,
bounds,
radius: defaultCoordinates.radius,
});
if (origin.locationName && origin.latitude && origin.longitude)
storage.origin = JSON.stringify({
locationName: origin.locationName,
latitude: origin.latitude,
longitude: origin.longitude,
});

storage.categoryIds = JSON.stringify(categoryIds);
storage.radius = JSON.stringify(radius);
storage.verified = JSON.stringify(isVerifiedSelected);
if (!center)
setViewport({
zoom: viewPortHash[radius || 0],
zoom: defaultCoordinates.zoom,
latitude: origin.latitude,
longitude: origin.longitude,
});
doSelectStakeholder(null);
},
[
search,
origin.locationName,
origin.latitude,
origin.longitude,
userCoordinates.latitude,
userCoordinates.longitude,
radius,
categoryIds,
isVerifiedSelected,
setViewport,
doSelectStakeholder,
viewPortHash,
storage.categoryIds,
storage.radius,
storage.verified,
storage.origin,
]
);

return (
<>
<Filters
radius={radius}
setRadius={setRadius}
origin={origin}
setOrigin={setOrigin}
toggleCategory={toggleCategory}
Expand All @@ -211,9 +140,6 @@ export default function ResultsContainer({
selectVerified={selectVerified}
userCoordinates={userCoordinates}
handleSearch={handleSearch}
viewport={viewport}
setViewport={setViewport}
viewPortHash={viewPortHash}
isMapView={isMapView}
switchResultsView={switchResultsView}
/>
Expand All @@ -229,16 +155,13 @@ export default function ResultsContainer({
{(!mobileView || (mobileView && isMapView)) && (
<Map
handleSearch={handleSearch}
selectedLatitude={initialCoords.latitude}
selectedLongitude={initialCoords.longitude}
viewport={viewport}
setViewport={setViewport}
stakeholders={data}
doSelectStakeholder={doSelectStakeholder}
selectedStakeholder={selectedStakeholder}
categoryIds={categoryIds}
setToast={setToast}
search={search}
/>
)}
</Grid>
Expand Down
Loading

0 comments on commit 4fe2a24

Please sign in to comment.