Overview

In this guide, we will see how to add a new page to a search UI created through the UI builder.

Pre-requisite: Create a Search UI

You can follow this 👇🏻 step-by-step tutorial to build a new Search UI, incase you already don't have one.



Now that we have a Search UI, Let's begin adding a route!! 🏎

Adding a new route

Code Snippets

Step 4: Add "hello-world" page key under the "pages" JSON object

Copy
"hello-world": "/hello-world"

Step 6: Create a new page "HelloWorld.js" under "src > pages" directory

Copy
import React from 'react';

const HelloWorld = () => {
    return <h1>Hello from new page! 👋🏻</h1>;
}

export default HelloWorld;

Step 7: Import HelloWorld.js from src/pages/ in App.js

Copy
import HelloWorld from './pages/HelloWorld';

Step 8: Add a new route '/hello-world' to "App.js" that renders "HelloWorld.js"

Copy
<Route path="/hello-world">
    <HelloWorld />
</Route>

Step 29: Add a new route '/hello-world' to "App.js" that renders "HelloWorld.js"

Copy
import React, { useState } from "react";
import { ReactiveBase, SearchBox } from "@appbaseio/reactivesearch";
import get from "lodash.get";
import { getSearchPreferences, defaultPreferences } from "../utils";
import { ResultsLayoutByCategory } from "@appbaseio/enterprise-search-ui";
import { Col, Row } from "antd";
import { css } from "@emotion/core";
import Filters from "../components/Filters";

const HelloWorld = () => {
  const [state, setState] = useState({
    searchAppState: {
      search_results: "",
      search_facets: {}
    }
  });
  const isMobile = () => {
    return window.innerWidth <= 768;
  };
  const preferences = getSearchPreferences();
  const pageSettings = get(preferences, "pageSettings", {});
  const pageEndpoint = get(
    pageSettings,
    `pages.${pageSettings.currentPage}.indexSettings.endpoint`
  );
  const index = get(preferences, "appbaseSettings.index");
  const credentials = get(preferences, "appbaseSettings.credentials");
  const url = get(preferences, "appbaseSettings.url");
  const theme = get(
    preferences,
    "themeSettings.rsConfig",
    defaultPreferences.themeSettings.rsConfig
  );
  const componentSettings = get(
    pageSettings,
    `pages.${pageSettings.currentPage}.componentSettings`,
    {}
  );

  const backend = get(preferences, "backend", "");
  const isFusion = backend === "fusion";

  const globalFusionSettings = get(preferences, "fusionSettings", {});
  const pageFusionSettings = get(
    pageSettings,
    `pages.${pageSettings.currentPage}.indexSettings.fusionSettings`
  );
  const fusionSettings = {
    ...globalFusionSettings,
    ...pageFusionSettings
  };
  const resultSettings = get(
    componentSettings,
    "result",
    get(preferences, "resultSettings", {})
  );
  const transformRequest = isFusion
    ? (props) => {
        if (Object.keys(fusionSettings).length) {
          const newBody = JSON.parse(props.body);
          newBody.metadata = {
            app: fusionSettings.app,
            profile: fusionSettings.profile,
            suggestion_profile: fusionSettings.searchProfile,
            sponsored_profile: get(fusionSettings, "meta.sponsoredProfile", "")
          };
          // eslint-disable-next-line
          props.body = JSON.stringify(newBody);
        }
        return props;
      }
    : undefined;
  let newProps = {};
  const sortOptionSelector = get(resultSettings, "sortOptionSelector", []);
  if (sortOptionSelector && sortOptionSelector.length) {
    newProps = {
      sortOptions: get(resultSettings, "sortOptionSelector")
    };
  }

  const searchSettings = get(
    componentSettings,
    "search",
    get(preferences, "searchSettings", {})
  );
  const searchStyles = ({ titleColor }) => css`
    .section-header > h3 {
      margin: 8px 0;
      color: ${titleColor};
      font-size: 16px;
    }
  `;
  let valueFields = ["term_s"];
  const defaultFields = get(resultSettings, "fields", {});
  if (defaultFields.title.dataField) {
    valueFields = [...valueFields, defaultFields.title.dataField];
  } else if (defaultFields.description.dataField) {
    valueFields = [...valueFields, defaultFields.description.dataField];
  }
  const searchIcon = get(searchSettings, "searchButton.icon", "");

  const currency = get(
    preferences,
    "globalSettings.currency",
    defaultPreferences.globalSettings.currency
  );

  const themeType = get(
    preferences,
    "themeSettings.type",
    defaultPreferences.themeSettings.type
  );

  const exportType = get(
    preferences,
    "exportSettings.type",
    defaultPreferences.exportType
  );

  const getFontFamily = () => {
    const receivedFont = get(theme, "typography.fontFamily", "");
    let fontFamily = "";
    if (receivedFont && receivedFont !== "default") {
      fontFamily = receivedFont; // eslint-disable-line
    }
    return fontFamily ? { fontFamily } : {};
  };

  const handleAppStateChange = (key, val) => {
    const { searchAppState } = state;
    const newSearchAppState = {
      ...JSON.parse(JSON.stringify(searchAppState))
    };

    if (key === "search") newSearchAppState.search_results = val;
    else if (Array.isArray(val)) {
      val.forEach((facet) => {
        newSearchAppState.search_facets[facet] = true;
      });
      Object.keys(newSearchAppState.search_facets).forEach((facet) => {
        if (!val.includes(facet))
          newSearchAppState.search_facets[facet] = false;
      });
    }

    setState({
      searchAppState: newSearchAppState
    });
  };

  return (
    <ReactiveBase
      endpoint={pageEndpoint}
      app={index}
      url={url}
      credentials={credentials}
      theme={theme}
      enableAppbase
      appbaseConfig={{
        recordAnalytics: true
      }}
      preferences={getSearchPreferences()}
      initialQueriesSyncTime={100}
      transformRequest={transformRequest}
    >
      <SearchBox
        preferencesPath={`pageSettings.pages.${pageSettings.currentPage}.componentSettings.search`}
        componentId="search"
        filterLabel="Search"
        className="search"
        debounce={100}
        placeholder={"Enter search query"}
        iconPosition="right"
        icon={
          searchIcon ? (
            <img
              src={searchIcon}
              alt="Search Icon"
              width="20px"
              height="20px"
            />
          ) : (
            searchIcon
          )
        }
        URLParams
        style={{
          margin: 20,
          position: "sticky",
          top: "10px",
          zIndex: 1000
        }}
        css={searchStyles(theme.colors)}
        popularSuggestionsConfig={{
          size: 3,
          sectionLabel: '<h3 class="section-label">Popular Suggestions</h3>'
        }}
        recentSuggestionsConfig={{
          size: 3,
          sectionLabel: '<h3 class="section-label">Recent Suggestions</h3>'
        }}
        enableIndexSuggestions
        indexSuggestionsConfig={{
          sectionLabel: '<h3 class="section-label">Index Suggestions</h3>',
          size: 3,
          valueFields
        }}
        size={6}
        showDistinctSuggestions
      />
      <Row gutter={2}>
        <Col span={6}>
          <Filters
            theme={theme}
            isMobile={isMobile}
            currency={currency}
            themeType={themeType}
            exportType={exportType}
            preferences={preferences}
            getFontFamily={getFontFamily()}
            pageSettings={pageSettings}
            handleAppStateChange={handleAppStateChange}
            searchAppState={state.searchAppState}
          />
        </Col>
        <Col span={18}>
          <ResultsLayoutByCategory
            preferences={preferences}
            toggleFilters={false}
            componentProps={{
              ...newProps,
              highlight: get(resultSettings, "resultHighlight", false)
            }}
          />
        </Col>
      </Row>
    </ReactiveBase>
  );
};

export default HelloWorld;