/** Initially this was written to support various location search providers in master, however we only have a single location provider at the moment, and how we merge them in the new design is yet to be resolved, see: https://github.com/TerriaJS/nsw-digital-twin/issues/248#issuecomment-599919318 */ import { observer } from "mobx-react"; import { FC, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import styled from "styled-components"; import isDefined from "../../Core/isDefined"; import { applyTranslationIfExists } from "../../Language/languageHelpers"; import LocationSearchProviderMixin from "../../ModelMixins/SearchProviders/LocationSearchProviderMixin"; import SearchProviderResult from "../../Models/SearchProviders/SearchProviderResults"; import SearchResultModel from "../../Models/SearchProviders/SearchResult"; import Terria from "../../Models/Terria"; import ViewState from "../../ReactViewModels/ViewState"; import Box, { BoxSpan } from "../../Styled/Box"; import { RawButton } from "../../Styled/Button"; import Icon, { StyledIcon } from "../../Styled/Icon"; import Ul from "../../Styled/List"; import Text, { TextSpan } from "../../Styled/Text"; import Loader from "../Loader"; import SearchHeader from "./SearchHeader"; import SearchResult from "./SearchResult"; const RawButtonAndHighlight = styled(RawButton)` ${(p) => ` &:hover, &:focus { background-color: ${p.theme.greyLighter}; ${StyledIcon} { fill-opacity: 1; } }`} `; interface LocationSearchResultsProps { viewState: ViewState; terria: Terria; searchResult: SearchProviderResult; onLocationClick: (result: SearchResultModel) => void; locationSearchText: string; } const LocationSearchResults: React.FC = observer( ({ searchResult, terria, locationSearchText, onLocationClick }: LocationSearchResultsProps) => { const [isExpanded, setIsExpanded] = useState(false); const toggleExpand = () => { setIsExpanded((prev) => !prev); }; const validResults = useMemo(() => { const locationSearchBoundingBox = terria.searchBarModel.boundingBoxLimit; let filterResults = false; let west: number | undefined, east: number | undefined, south: number | undefined, north: number | undefined; if (locationSearchBoundingBox) { ({ west, east, south, north } = locationSearchBoundingBox); filterResults = isDefined(west) && isDefined(east) && isDefined(south) && isDefined(north); } const validResults = filterResults ? searchResult.results.filter(function (r: any) { return ( r.location.longitude > west! && r.location.longitude < east! && r.location.latitude > south! && r.location.latitude < north! ); }) : searchResult.results; return validResults; }, [searchResult.results, terria]); const searchProvider: LocationSearchProviderMixin.Instance = searchResult.searchProvider as unknown as LocationSearchProviderMixin.Instance; const maxResults = searchProvider.recommendedListLength || 5; const results = validResults.length > maxResults ? isExpanded ? validResults : validResults.slice(0, maxResults) : validResults; const isOpen = searchProvider.isOpen; return ( searchProvider.toggleOpen()} > {isOpen && ( <>
    {results.map((result: SearchResultModel, i: number) => ( ))}
{validResults.length > maxResults && ( )} )}
); } ); interface SearchResultsFooterProps { isExpanded: boolean; name: string; } const SearchResultsFooter: FC = ( props: SearchResultsFooterProps ) => { const { t, i18n } = useTranslation(); if (props.isExpanded) { return t("search.viewLess", { name: applyTranslationIfExists(props.name, i18n) }); } return t("search.viewMore", { name: applyTranslationIfExists(props.name, i18n) }); }; interface NameWithLoaderProps { name: string; length?: number; isOpen: boolean; search: SearchProviderResult; } const NameWithLoader: FC = observer( (props: NameWithLoaderProps) => { const { i18n } = useTranslation(); return ( {`${applyTranslationIfExists(props.name, i18n)} ${ !props.search.isWaitingToStartSearch ? `(${props.length || 0})` : "" }`} {!props.isOpen && (props.search.isSearching || props.search.isWaitingToStartSearch) && ( )} ); } ); export default LocationSearchResults;