-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #979 from CodeForAfrica/chore/hero-mobile-fix
FIxed Hero Mobile styles.
- Loading branch information
Showing
7 changed files
with
268 additions
and
257 deletions.
There are no files selected for viewing
186 changes: 186 additions & 0 deletions
186
apps/climatemappedafrica/src/components/DropdownSearch/DownloadSearch.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
import { | ||
IconButton, | ||
InputBase, | ||
Typography, | ||
List, | ||
ListItem, | ||
SvgIcon, | ||
Box, | ||
} from "@mui/material"; | ||
import { useRouter } from "next/router"; | ||
import PropTypes from "prop-types"; | ||
import React, { useEffect, useState } from "react"; | ||
|
||
import SearchIcon from "@/climatemappedafrica/assets/icons/search.svg"; | ||
import Link from "@/climatemappedafrica/components/Link"; | ||
|
||
function DropdownSearch({ | ||
href: hrefProp = "/explore", | ||
label = "Search for a location", | ||
locations, | ||
onClick, | ||
icon: IconProp = SearchIcon, | ||
placeholder, | ||
variant, | ||
...props | ||
}) { | ||
const router = useRouter(); | ||
const [query, setQuery] = useState(""); | ||
const [selectedLocation, setSelectedLocation] = useState(null); | ||
const [suggestions, setSuggestions] = useState([]); | ||
|
||
const handleChange = (e) => { | ||
setQuery(e.target.value); | ||
setSelectedLocation(null); | ||
}; | ||
|
||
const handleSelect = (code, name) => { | ||
setQuery(name.toLowerCase()); | ||
setSelectedLocation(code); | ||
if (code && hrefProp?.length) { | ||
router.push(`${hrefProp}/${code}`); | ||
} | ||
}; | ||
|
||
useEffect(() => { | ||
if (query?.length > 0 && !selectedLocation) { | ||
const matchedGeo = locations?.filter(({ name }) => | ||
name.toLowerCase()?.startsWith(query.toLowerCase()), | ||
); | ||
setSuggestions(matchedGeo); | ||
} else { | ||
setSuggestions([]); | ||
} | ||
}, [locations, selectedLocation, query]); | ||
|
||
const handleClickSearch = () => { | ||
if (onClick) { | ||
onClick(selectedLocation); | ||
} else if (selectedLocation) { | ||
const href = `${hrefProp}/${selectedLocation}`; | ||
router.push(href); | ||
} else if (query) { | ||
router.push("/404"); | ||
} | ||
}; | ||
|
||
let iconComponent = SearchIcon; | ||
let iconBorder; | ||
if (variant === "explore") { | ||
iconComponent = IconProp; | ||
iconBorder = { | ||
borderRadius: "50%", | ||
border: "2px solid #fff", | ||
}; | ||
} | ||
const searchIconButton = ( | ||
<IconButton | ||
color="primary" | ||
onClick={handleClickSearch} | ||
size="small" | ||
sx={() => ({ | ||
padding: 0, | ||
ml: 2, | ||
})} | ||
> | ||
<SvgIcon | ||
component={iconComponent} | ||
viewBox="0 0 48 48" | ||
sx={{ | ||
width: 48, | ||
height: 48, | ||
...iconBorder, | ||
}} | ||
/> | ||
</IconButton> | ||
); | ||
|
||
return ( | ||
<Box id="location-search"> | ||
<Typography | ||
variant="body1" | ||
sx={({ palette, typography }) => ({ | ||
color: palette.text.primary, | ||
marginBottom: typography.pxToRem(10), | ||
})} | ||
> | ||
{label} | ||
</Typography> | ||
<InputBase | ||
inputProps={{ "aria-label": "search" }} | ||
onChange={handleChange} | ||
placeholder={placeholder} | ||
value={query} | ||
{...props} | ||
sx={({ typography, palette }) => ({ | ||
borderRadius: typography.pxToRem(10), | ||
color: palette.primary.main, | ||
border: `2px solid ${palette.text.hint}`, | ||
width: typography.pxToRem(278), | ||
backgroundColor: "inherit", | ||
height: typography.pxToRem(48), | ||
padding: `0 ${typography.pxToRem(20)}`, | ||
"&.MuiInputBase-input": { | ||
backgroundColor: "inherit", | ||
height: typography.pxToRem(48), | ||
borderRadius: typography.pxToRem(10), | ||
padding: `0 ${typography.pxToRem(20)}`, | ||
textTransform: "capitalize", | ||
}, | ||
"&.Mui-focused": { | ||
border: `2px solid ${palette.primary.main}`, | ||
}, | ||
...props.sx, | ||
})} | ||
endAdornment={variant === "explore" ? searchIconButton : null} | ||
/> | ||
{variant !== "explore" && searchIconButton} | ||
|
||
<Box sx={{ position: "relative" }}> | ||
{suggestions?.length > 0 && ( | ||
<List | ||
sx={({ typography, palette }) => ({ | ||
width: typography.pxToRem(278), | ||
position: "absolute", | ||
marginTop: typography.pxToRem(5), | ||
zIndex: 10, | ||
background: palette.background.default, | ||
border: `2px solid ${palette.grey.main}`, | ||
borderRadius: typography.pxToRem(10), | ||
padding: 0, | ||
textTransform: "capitalize", | ||
})} | ||
> | ||
{suggestions.map(({ name, code }) => ( | ||
<ListItem | ||
component={Link} | ||
variant="subtitle1" | ||
underline="none" | ||
onClick={() => handleSelect(code, name)} | ||
sx={({ typography, palette }) => ({ | ||
paddingLeft: typography.pxToRem(20), | ||
color: palette.text.hint, | ||
})} | ||
key={code} | ||
> | ||
{name.toLowerCase()} | ||
</ListItem> | ||
))} | ||
</List> | ||
)} | ||
</Box> | ||
</Box> | ||
); | ||
} | ||
|
||
DropdownSearch.propTypes = { | ||
label: PropTypes.string, | ||
href: PropTypes.string, | ||
onClick: PropTypes.func, | ||
icon: PropTypes.elementType, | ||
locations: PropTypes.arrayOf(PropTypes.shape({})), | ||
variant: PropTypes.string, | ||
placeholder: PropTypes.string, | ||
}; | ||
|
||
export default DropdownSearch; |
46 changes: 46 additions & 0 deletions
46
apps/climatemappedafrica/src/components/DropdownSearch/DropdownSearch.snap.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`<DropdownSearch /> renders unchanged 1`] = ` | ||
<div> | ||
<div | ||
class="MuiBox-root css-0" | ||
id="location-search" | ||
> | ||
<p | ||
class="MuiTypography-root MuiTypography-body1 css-1u0kiq2-MuiTypography-root" | ||
> | ||
Search for a location | ||
</p> | ||
<div | ||
class="MuiInputBase-root MuiInputBase-colorPrimary MuiInputBase-adornedEnd css-78q71b-MuiInputBase-root" | ||
> | ||
<input | ||
aria-label="search" | ||
class="MuiInputBase-input MuiInputBase-inputAdornedEnd css-yz9k0d-MuiInputBase-input" | ||
placeholder="Search for a location" | ||
type="text" | ||
value="" | ||
/> | ||
<button | ||
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorPrimary MuiIconButton-sizeSmall css-oru44q-MuiButtonBase-root-MuiIconButton-root" | ||
root="[object Object]" | ||
tabindex="0" | ||
type="button" | ||
> | ||
<svg | ||
aria-hidden="true" | ||
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-kzlhbf-MuiSvgIcon-root" | ||
focusable="false" | ||
viewBox="0 0 48 48" | ||
/> | ||
<span | ||
class="MuiTouchRipple-root css-8je8zh-MuiTouchRipple-root" | ||
/> | ||
</button> | ||
</div> | ||
<div | ||
class="MuiBox-root css-79elbk" | ||
/> | ||
</div> | ||
</div> | ||
`; |
25 changes: 25 additions & 0 deletions
25
apps/climatemappedafrica/src/components/DropdownSearch/DropdownSearch.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { createRender } from "@commons-ui/testing-library"; | ||
import React from "react"; | ||
|
||
import DropdownSearch from "./DownloadSearch"; | ||
|
||
import theme from "@/climatemappedafrica/theme"; | ||
|
||
// eslint-disable-next-line testing-library/render-result-naming-convention | ||
const render = createRender({ theme }); | ||
|
||
const defaultProps = { | ||
href: "/explore", | ||
label: "Search for a location", | ||
locations: [], | ||
icon: null, | ||
placeholder: "Search for a location", | ||
variant: "explore", | ||
}; | ||
|
||
describe("<DropdownSearch />", () => { | ||
it("renders unchanged", () => { | ||
const { container } = render(<DropdownSearch {...defaultProps} />); | ||
expect(container).toMatchSnapshot(); | ||
}); | ||
}); |
Oops, something went wrong.