DEV Community

AmasiaNalbandian
AmasiaNalbandian

Posted on

Planning a feature enhancement... continued (3/?)

Recap

As we left off the last post, we saw that I was able to complete items 2,3, and 4 from the four things we want to implement:

  1. Continue to build off the previously created UI for the advanced search.
  2. I want to implement the search by date, once I have this down I should understand how to further leverage the implementation of Elasticsearch to implement more.
  3. Let's try to implement search by Semester, or date range.
  4. I explored some queries on the Elasticsearch container in docker, and realized we can pass more than just one parameter

Next, we need to work on the front end and the UI for the search to work.

Front-End UI

I went ahead and picked the changes for the front end from the PR I mentioned in the first post. From there, I made some refinements and voila we have the following:
searchbar

Now when you click on the advanced search text, I played around with this bit mostly so that it was a little more user-friendly.

advanced search dialogue

Wiring backend with front

Luckily this bit was really easy(obviously needs some padding and alignment). However, as I mentioned in the last post, we run through two containers to make a search request - Elasticsearch and search. Elasticsearch is all ready and complete, however for the communication to happen from the web app to search is a little tricky.

The search uses a file called SearchProvider and has Hooks also. However we introduced more fields to search by, and those need to be included. Essentially, there needs to be a huge refactoring of the search provider to fit the changes made, mainly due to the submitHandler for the fields:

  const onSubmitHandler = (event: FormEvent) => {
    event.preventDefault();
    router.push(`/search?text=${text}&filter=${filter}`);
  };
Enter fullscreen mode Exit fullscreen mode

As you can see, the route here is /search. If you look at the previous posts you will see that the new route for the advancedsearch is /advanced/. We need to stop and consider some things here before we proceed. We can either try to salvage this and create a lot of spaghetti (code), or we really need to refactor everything as the new route will also cover the old route requirements.

Step 1

I completely threw out the SearchInput.tsx file. Why? We don't need it. Every field has its own value now. I don't have any more inputs to switch. This meant that the SearchBar.tsx will no longer allow users to decide from author or post, but it will be posts only. If we want this to be a very general search, where I write "Elasticsearch", and it searches all fields - we can do this too.

Step 2

I started to change around the values that were passed in for the Provider. I began by pulling in my DateSearchInput changes from the first PR, and put in the new values in Search provider so it looked like this now:

const SearchProvider = ({ children }: Props) => {
  const router = useRouter();
  // We synchronize the `text` and `filter` values to the URL's query string
  // Router query object for a query can be an array if url becomes text=123&text=456
  // https://stackoverflow.com/questions/60110364/type-string-string-is-not-assignable-to-type-string
  const textParam = Array.isArray(router.query.text)
    ? router.query.text[0]
    : router.query.text || '';
  const filterParam = getFilter(router.query.filter);

  // We manage the state of `text` and `filter` internally, and update URL on
  // form submit only.  These are used in the <SearchBar>, and the user can change them.
  const [post, setPost] = useState<string>('');
  const [author, setAuthor] = useState<string>('');
  const [startDate, setStartDate] = useState<string>('');
  const [endDate, setEndDate] = useState<string>('');

  const [showHelp, setShowHelp] = useState(true);

  const onSubmitHandler = (event: FormEvent) => {
    event.preventDefault();
     router.push(
       `/search?postText=${post}&authorText=${author}&endDate=${endDate}&startDate=${startDate}`
     );
  };

  const toggleHelp = (value: boolean) => {
    setShowHelp(value);
  };

  const onPostChange = (value: string) => {
    setPost(value);
    console.log('sailoe');
  };

  const onAuthorChange = (value: string) => {
    setAuthor(value);
  };

  const onStartDateChange = (value: string) => {
    setStartDate(value);
  };

  const onEndDateChange = (value: string) => {
    setEndDate(value);
  };

  useEffect(() => {
    setPost(textParam);
    setAuthor(textParam);
    setStartDate(textParam);
    setEndDate(textParam);
  }, [textParam, filterParam]);

  return (
    <SearchContext.Provider
      value={{
        post,
        author,
        startDate,
        endDate,
        showHelp,
        toggleHelp,
        onPostChange,
        onAuthorChange,
        onStartDateChange,
        onEndDateChange,
        onSubmitHandler,
      }}
    >
      {children}
    </SearchContext.Provider>
  );
};

Enter fullscreen mode Exit fullscreen mode

As you can see, we now store the post, author, and dates separately, and no longer under the text, textParam and filter values. This allows us to leverage each field individually in the application, allowing us to search with multiple fields (as we designed the Elasticsearch query to work).

Step 3: Roadblocked?

At this point, I need to take a small break and look at this again. Many changes were made made for this refactoring, and the search bars are all doing something funny. Currently, they are all sending requests at every character which I change or add, but I have all the handlers commented out. This is not efficient at all. I am pretty certain I am close to refactoring most of this, and the really rough PR can be seen here, however, for now we can definitely look at the backend and get that in. I have opened up a new issue to continue to tackle the front end.

Summary:

It's clear that the feature I picked required a lot of work, but honestly I am quite impressed with how far it has come along. I did not expect the provider to cause me any disruptions, as it was written to do the opposite, but I have clearly introduced many new enhancements which have to be factored into that.

At the beginning, in my first post I wrote two things I wanted to keep in mind:

1) Don't get carried away trying to implement the most advanced search ever; break things up.
2) Explore the most useful search criterion that would make the advanced search more meaningful for visitors on the site.

I definitely feel that I did both of these things, however, if I could add one more - Don't believe that everything needs to happen at once. It was a little foolish of me and reckless to put the weight of the backend, and the front end in a week. Could it have been done? Yeah, but most times I forget I am human and I too need time to reset my brain.

I will most likely continue to tackle this refactoring, as it's mostly complete, just has a few tweaks to fix. I am quite impressed with how possible it was to do an advanced search, and something I didn't think I'd be able to put on my list of "I've done this!". Every opportunity to learn something new is always exciting, tiring, emotional, but most importantly rewarding - and that is why I come back.

Top comments (0)