Skip to content

Commit

Permalink
Merge pull request #963 from CodeForAfrica/ft/climatemapped-explore-page
Browse files Browse the repository at this point in the history
ClimateMapped: Explore Page
  • Loading branch information
kelvinkipruto authored Oct 25, 2024
2 parents ee13cbf + 8a6a313 commit a1e011c
Show file tree
Hide file tree
Showing 17 changed files with 417 additions and 98 deletions.
84 changes: 66 additions & 18 deletions apps/climatemappedafrica/src/components/ExplorePage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,37 @@ import useStyles from "./useStyles";

import Panel from "@/climatemappedafrica/components/HURUmap/Panel";

function initialState(profiles, onClick) {
function initialState(
profiles,
onClick,
explorePagePath,
initialLocationCode,
pinInitialLocation,
) {
return {
profiles: Array.isArray(profiles) ? profiles : [profiles],
options: [
{ color: "primary", onClick },
{ color: "secondary", onClick },
],
explorePagePath,
initialLocationCode,
pinInitialLocation,
};
}

function ExplorePage({ panelProps, profile: profileProp, apiUri, ...props }) {
function ExplorePage({
initialLocation,
explorePagePath,
panel: PanelProps = {},
profile: profileProp,
...props
}) {
const {
center,
name: initialLocationCode,
pinInitialLocation,
} = initialLocation;
const theme = useTheme();
const classes = useStyles(props);
// NOTE: This setState and the corresponding useEffect are "hacks" since at
Expand All @@ -32,23 +52,43 @@ function ExplorePage({ panelProps, profile: profileProp, apiUri, ...props }) {
setGeoCode(code);
};
const [state, dispatch] = useExplore(
initialState(profileProp, handleClickTag),
initialState(
profileProp,
handleClickTag,
explorePagePath,
initialLocationCode,
pinInitialLocation,
),
);
useEffect(() => {
dispatch({
type: "reset",
payload: initialState(profileProp, handleClickTag),
payload: initialState(
profileProp,
handleClickTag,
explorePagePath,
initialLocationCode,
pinInitialLocation,
),
});
}, [dispatch, profileProp]);
}, [
dispatch,
profileProp,
explorePagePath,
initialLocationCode,
pinInitialLocation,
]);
useEffect(() => {
if (geoCode) {
dispatch({ type: "fetch", payload: { code: geoCode } });
}
}, [dispatch, geoCode]);

const router = useRouter();
const shouldFetch = () =>
(state.primary.shouldFetch && state.primary.code) ||
(state.secondary?.shouldFetch && state.secondary?.code);

const { data, error } = useProfileGeography(shouldFetch);
useEffect(() => {
if (data) {
Expand All @@ -59,13 +99,23 @@ function ExplorePage({ panelProps, profile: profileProp, apiUri, ...props }) {
}
}, [dispatch, data]);

// Update URL when state.slug changes
useEffect(() => {
if (state.slug) {
const href = `/${explorePagePath}/${state.slug}`;
router.push(href, href, { shallow: true });
}
// router shouldn't part of useEffect dependencies: https://nextjs.org/docs/api-reference/next/router#userouter
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [state.slug]);

const handleSelectLocation = (payload) => {
const { code } = payload;
const newPath =
state.isPinning || state.isCompare
? `${state.primary.geography.code}-vs-${code}`
: `${code}`;
const href = `/explore/${newPath.toLowerCase()}`;
const href = `/${explorePagePath}/${newPath.toLowerCase()}`;
router.push(href, href, { shallow: true });
const type = state.isPinning && state.isCompare ? "compare" : "fetch";
dispatch({ type, payload });
Expand All @@ -86,14 +136,6 @@ function ExplorePage({ panelProps, profile: profileProp, apiUri, ...props }) {
}
dispatch({ type: "unpin", payload });
};
useEffect(() => {
if (state.slug) {
const href = `/explore/${state.slug}`;
router.push(href, href, { shallow: true });
}
// router shouldn't part of useEffect dependencies: https://nextjs.org/docs/api-reference/next/router#userouter
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [state.slug]);

const isLoading = shouldFetch() && !(data || error);
const {
Expand All @@ -119,7 +161,7 @@ function ExplorePage({ panelProps, profile: profileProp, apiUri, ...props }) {
>
<div className={classes.root}>
<Map
center={[0.3051933453207569, 37.908818734483155]}
center={center}
geography={geography}
secondaryGeography={state.secondary?.geography}
geometries={geometries}
Expand Down Expand Up @@ -159,15 +201,21 @@ function ExplorePage({ panelProps, profile: profileProp, apiUri, ...props }) {
onSelectLocation={handleSelectLocation}
primaryProfile={state.primary}
secondaryProfile={state.secondary}
{...panelProps}
{...PanelProps}
/>
</>
);
}

ExplorePage.propTypes = {
apiUri: PropTypes.string,
panelProps: PropTypes.shape({}),
center: PropTypes.arrayOf(PropTypes.number),
initialLocation: PropTypes.shape({
center: PropTypes.arrayOf(PropTypes.number),
name: PropTypes.string,
pinInitialLocation: PropTypes.bool,
}),
explorePagePath: PropTypes.string,
panel: PropTypes.shape({}),
profile: PropTypes.oneOfType([
PropTypes.shape({
geography: PropTypes.shape({}),
Expand Down
46 changes: 32 additions & 14 deletions apps/climatemappedafrica/src/components/ExplorePage/useExplore.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useReducer } from "react";

import Link from "@/climatemappedafrica/components/Link";

function extendProfileTags(profile, options) {
function extendProfileTags(profile, options, explorePagePath) {
const { tags: originalTags, ...other } = profile || {};
if (!originalTags) {
return profile;
Expand All @@ -12,27 +12,37 @@ function extendProfileTags(profile, options) {
...otherTags,
code,
component: Link,
href: `/explore/${code.toLowerCase()}`,
href: `/${explorePagePath}/${code.toLowerCase()}`,
shallow: true,
underline: "none",
...options,
}));
return { ...other, tags };
}

function initializer({ profiles, options }) {
function initializer({
explorePagePath,
initialLocationCode,
profiles,
pinInitialLocation,
options,
}) {
const [primary, secondary] = profiles;
const [primaryOptions, secondaryOptions] = options;

return {
isPinning: false,
isCompare: !!(primary && secondary),
primary: extendProfileTags(primary, primaryOptions),
secondary: extendProfileTags(secondary, secondaryOptions),
primary: extendProfileTags(primary, primaryOptions, explorePagePath),
secondary: extendProfileTags(secondary, secondaryOptions, explorePagePath),
explorePagePath,
initialLocationCode,
pinInitialLocation,
};
}

function reducer(state, action) {
const { explorePagePath, initialLocationCode, pinInitialLocation } = state;
switch (action.type) {
case "fetch": {
const code = action.payload?.code;
Expand Down Expand Up @@ -67,21 +77,25 @@ function reducer(state, action) {
);
if (profileType) {
const newState = { ...state };
newState[profileType] = extendProfileTags(profile, {
...others,
color: profileType,
});
newState[profileType] = extendProfileTags(
profile,
{
...others,
color: profileType,
},
explorePagePath,
);
return newState;
}
}

return state;
}
case "pin":
if (state.primary.geography.code.toLowerCase() !== "af") {
if (state.primary.geography.code.toLowerCase() !== initialLocationCode) {
return { ...state, isPinning: true };
}
return { ...state, isPinning: false };
return { ...state, isPinning: pinInitialLocation };
case "compare": {
const code = action.payload?.code;
if (code) {
Expand All @@ -101,9 +115,13 @@ function reducer(state, action) {
newState.secondary = undefined;
} else if (state.primary?.geography?.code === code && state.secondary) {
// NOTE: need to reset color from secondary back to primary as well
newState.primary = extendProfileTags(state.secondary, {
color: "primary",
});
newState.primary = extendProfileTags(
state.secondary,
{
color: "primary",
},
explorePagePath,
);
newState.secondary = undefined;
}
newState.secondary = undefined;
Expand Down
3 changes: 2 additions & 1 deletion apps/climatemappedafrica/src/components/Hero/Hero.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ import Section from "@/climatemappedafrica/components/Section";
const Map = dynamic(() => import("./Map"), { ssr: false });

function Hero({
center,
comment,
title,
subtitle,
searchLabel,
featuredLocations,
searchPlaceholder,
properties,
location: { center },
level,
...props
}) {
Expand Down Expand Up @@ -151,6 +151,7 @@ function Hero({
}

Hero.propTypes = {
center: PropTypes.arrayOf(PropTypes.number),
comment: PropTypes.string,
subtitle: PropTypes.arrayOf(PropTypes.shape({})),
searchLabel: PropTypes.string,
Expand Down
1 change: 1 addition & 0 deletions apps/climatemappedafrica/src/components/Hero/Hero.snap.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ exports[`<Hero /> renders unchanged 1`] = `
blocktype="hero"
boundary="[object Object]"
class="MuiInputBase-root makeStyles-inputRoot-8 MuiInputBase-colorPrimary MuiInputBase-adornedEnd css-1illudf-MuiInputBase-root"
location="[object Object]"
slug="hero"
>
<input
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const useStyles = makeStyles(({ palette, typography }) => ({
},
}));

function ExploreNavigation({ logo, variant }) {
function ExploreNavigation({ explorePagePath, logo, variant }) {
const classes = useStyles();
const { setIsOpen } = useTour();

Expand Down Expand Up @@ -71,6 +71,7 @@ function ExploreNavigation({ logo, variant }) {
>
<DropdownSearch
icon={SearchIcon}
href={explorePagePath}
placeholder="Search for a Location" // TODO: Read from cms
variant={variant}
classes={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,14 @@ const Transition = React.forwardRef(function Transition(props, ref) {
return <Slide direction="left" timeout={1000} ref={ref} {...props} />;
});

function MobileNavigation({ drawerLogo, logo, menus, socialLinks, ...props }) {
function MobileNavigation({
drawerLogo,
explorePagePath,
logo,
menus,
socialLinks,
...props
}) {
const classes = useStyles(props);
const [open, setOpen] = useState(false);
const router = useRouter();
Expand Down Expand Up @@ -277,6 +284,7 @@ function MobileNavigation({ drawerLogo, logo, menus, socialLinks, ...props }) {
}}
>
<DropdownSearch
href={explorePagePath}
classes={{
root: classes.search,
inputRoot: classes.searchInput,
Expand Down
Loading

0 comments on commit a1e011c

Please sign in to comment.