Skip to content

Commit

Permalink
Fix mobile search UI (#7022)
Browse files Browse the repository at this point in the history
* Fixed a bug.

* Update yarn.lock.

* Added unit tests.

* Updated doc.

* Fixed CI build errors.

* Fixed CI build error.

* Minor improvement.

* Minor improvement.
  • Loading branch information
mwu2018 authored Jan 9, 2024
1 parent dc76940 commit 9379fc9
Show file tree
Hide file tree
Showing 5 changed files with 878 additions and 815 deletions.
5 changes: 4 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,10 @@
"no-array-constructor": "error",
"no-new-object": 1,
"no-unneeded-ternary": 1 /* ECMAScript 6 */,
"prefer-const": "error"
"prefer-const": "error",
/* See https://stackoverflow.com/questions/64646248/eslintrc-js-for-react-17-and-jsx-without-import-react/64646593#64646593 */
"react/jsx-uses-react": "off",
"react/react-in-jsx-scope": "off"
},
"overrides": [
{
Expand Down
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- Fixed regression causing explorer window not to display instructions when first opened.
- [The next improvement]
- Enable eslint for typescript: plugin:@typescript-eslint/eslint-recommended
- Fixed a bug where the search box was missing for small screen devices.
- Prevent user adding empty web url
- Fix bug where search results shown in `My Data` tab

Expand Down
55 changes: 28 additions & 27 deletions lib/ReactViews/Mobile/MobileHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,34 +129,35 @@ class MobileHeader extends React.Component {

renderSearch() {
const { t, viewState } = this.props;

const searchState = viewState.searchState;
<div className={Styles.formSearchData}>
{searchState.showMobileLocationSearch && (
<SearchBox
searchText={searchState.locationSearchText}
onSearchTextChanged={this.changeLocationSearchText.bind(this)}
onDoSearch={this.searchLocations.bind(this)}
placeholder={applyTranslationIfExists(
viewState.terria.searchBarModel.placeholder,
this.props.i18n
)}
alwaysShowClear
onClear={this.closeLocationSearch.bind(this)}
autoFocus
/>
)}
{searchState.showMobileCatalogSearch && (
<SearchBox
searchText={searchState.catalogSearchText}
onSearchTextChanged={this.changeCatalogSearchText.bind(this)}
onDoSearch={this.searchCatalog.bind(this)}
placeholder={t("search.searchCatalogue")}
onClear={this.closeCatalogSearch.bind(this)}
autoFocus
/>
)}
</div>;
return (
<div className={Styles.formSearchData}>
{searchState.showMobileLocationSearch && (
<SearchBox
searchText={searchState.locationSearchText}
onSearchTextChanged={this.changeLocationSearchText.bind(this)}
onDoSearch={this.searchLocations.bind(this)}
placeholder={applyTranslationIfExists(
viewState.terria.searchBarModel.placeholder,
this.props.i18n
)}
alwaysShowClear
onClear={this.closeLocationSearch.bind(this)}
autoFocus
/>
)}
{searchState.showMobileCatalogSearch && (
<SearchBox
searchText={searchState.catalogSearchText}
onSearchTextChanged={this.changeCatalogSearchText.bind(this)}
onDoSearch={this.searchCatalog.bind(this)}
placeholder={t("search.searchCatalogue")}
onClear={this.closeCatalogSearch.bind(this)}
autoFocus
/>
)}
</div>
);
}

render() {
Expand Down
86 changes: 86 additions & 0 deletions test/ReactViews/Mobile/MobileHeaderSpec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import MobileHeader from "../../../lib/ReactViews/Mobile/MobileHeader";
import { act } from "react-dom/test-utils";
import { ReactTestRenderer } from "react-test-renderer";
import Terria from "../../../lib/Models/Terria";
import ViewState from "../../../lib/ReactViewModels/ViewState";
import { createWithContexts } from "../withContext";
import processCustomElements from "../../../lib/ReactViews/StandardUserInterface/processCustomElements";
import SearchBox from "../../../lib/ReactViews/Search/SearchBox";
import i18next, { i18n } from "i18next";

describe("MobileHeader", function () {
let terria: Terria;
let viewState: ViewState;
let i18n: i18n;

beforeEach(async function () {
terria = new Terria({
baseUrl: "./"
});
terria;
viewState = new ViewState({
terria: terria,
catalogSearchProvider: undefined
});
i18n = i18next.createInstance();
await i18n.init();
});

let testRenderer: ReactTestRenderer;

it("should render search for locations for small screen", function () {
const isSmallScreen = true;
const customElements = processCustomElements(isSmallScreen, undefined);

viewState.searchState.showMobileLocationSearch = true;

act(() => {
testRenderer = createWithContexts(
viewState,
<MobileHeader
menuItems={customElements.menu}
menuLeftItems={customElements.menuLeft}
i18n={i18n}
/>
);
});

const searchBox = testRenderer.root.findAllByType(SearchBox);
expect(searchBox.length).toBe(1);
expect(searchBox[0].props.alwaysShowClear).toBe(true);
expect(searchBox[0].props.autoFocus).toBe(true);
expect(searchBox[0].props.searchText).toBe("");
expect(searchBox[0].props.placeholder).toBe("search.placeholder");
// CI GabrielBB/xvfb test does not check name properly.
expect(searchBox[0].props.onDoSearch.name).toBeDefined(); //.toBe("bound searchLocations");
expect(searchBox[0].props.onSearchTextChanged.name).toBeDefined(); //.toBe("bound changeLocationSearchText");
expect(searchBox[0].props.onClear.name).toBeDefined(); //.toBe("bound closeLocationSearch");
});

it("should render search for catalogue for small screen", function () {
const isSmallScreen = true;
const customElements = processCustomElements(isSmallScreen, undefined);

viewState.searchState.showMobileCatalogSearch = true;

act(() => {
testRenderer = createWithContexts(
viewState,
<MobileHeader
menuItems={customElements.menu}
menuLeftItems={customElements.menuLeft}
/>
);
});

const searchBox = testRenderer.root.findAllByType(SearchBox);
expect(searchBox.length).toBe(1);
expect(searchBox[0].props.autoFocus).toBe(true);
expect(searchBox[0].props.searchText).toBe("");
expect(searchBox[0].props.placeholder).toBe("search.searchCatalogue");
// CI GabrielBB/xvfb test does not check name properly.
expect(searchBox[0].props.onDoSearch.name).toBeDefined(); //.toBe("bound searchCatalog");
expect(searchBox[0].props.onSearchTextChanged.name).toBeDefined(); //.toBe("bound changeCatalogSearchText");
expect(searchBox[0].props.onClear.name).toBeDefined(); //.toBe("bound closeCatalogSearch");
});
});
Loading

0 comments on commit 9379fc9

Please sign in to comment.