Mini contact cards - using Algolia as the search service and setting the web app up as a PWA
Tags: react, javascript, algolia, webdev
Published: 2020-02-19 21:50:43

Hello everyone,

This tutorial will be about getting few details from a JSON object as mini contact cards using the front-end technology(react) and a search engine(algolia). The app will be hosted on netlify.

**A quick note:**

Algolia is a powerful search-service because the set up is quite easy, powerful, produces excellent search results and allows users to have a wonderful search experience. 

---------------------------------------

### Let's get started:

-Make sure Node.js installed on your computer
- Set up react using this command - `npx create-react-app .` _not_ `npx create-react-app my-app` because the later command will install a folder into the folder you already specified and we want the folder structure to look like this:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/rhmah88h8ilvfaodbl8h.PNG)
Read more:- `https://create-react-app.dev/docs/getting-started/`

In the _App.js_ file, refactor the code to the following code:

```
import React, { Component} from 'react';
import './App.css';

class App extends Component {
    
    render(){
    return (
      <div className="App">
          <p>Random contact card</p>
    </div>
    );
    }
  }

  export default App;

```
We only need to render the title of the app for now. 

Add this to the _App.css_ file:

```
p {
    font-size: 50px;
    color: rgb(164, 193, 188);
    text-align: center
  }

```

In the _index.css_ file, refactor the code to the following code:

```
body {
  margin: 0;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

```

An account needs to be created on algolia and once that is created, you will be redirected to a dashboard.

Create an index titled -, _for example: search-details._

Under _add records to search_, there are three options, `add records manually`, `use the API` or `upload file`. 

We will be `uploading the records manually` since they are just ten users we are trying to search for.

Paste this JSON URL in your browser to get the full data: `http://jsonplaceholder.typicode.com/users`

After the full data have been copied, paste it to the algolia console and click save.

Click on _searchable attributes_ and add the attributes to be used in searching. 
Tip: you can add name and email since that is what will only be searched for.
Review and save settings.

Create a folder called components and create another folder called _search_, in it, create two files called - `search.component.jsx` and `search.style.css` in the search folder.

Install these packages:
 `npm install aloglia search react-instantsearch-dom -S` - to integrate the Javascript API client and for helping to search the react-dom.

Add this following code to the search.component.jsx file:

```
import React from 'react';
import algoliasearch from 'algoliasearch/lite';
import { InstantSearch, SearchBox} from 'react-instantsearch-dom';
import {Content} from '../content/content.component';
import './search.style.css';

const searchClient = algoliasearch(
  '_APP ID_',
  '_Search-Only API Key_'
);
export const Search = () => (
  <InstantSearch searchClient={searchClient} indexName="search-details">
         <SearchBox 
            className='search' 
            />
     <Content 
     />    
  </InstantSearch>
);

```
`algolisearch app id` and `key` are assigned to a constant whereby a function is declared to use the `instantsearch` component, retrieve the `searchClient` and index of the records. 
The `searchBox` is a widget used to let the user perform a text-based query - will be used for searching through the records.

Add this code to the search.style.css:

```
input[type='search'] {
    justify-content: center;
    padding: 10px 30px;
    width: 40%;
    border: 1px solid black;
    margin-left: 30%;
  }

button.ais-SearchBox-submit {
      display: none;
  }

button.ais-SearchBox-reset{
  display: none;
}  

```

----------------------------------------

Back to the components folder:

Create a folder called _content_, in it, create two files called: `content.component.jsx` and `content.style.css`.

Add the following code to the content.component.jsx file:

```
import React from 'react';
import { Hits } from 'react-instantsearch-dom';
import { Hit } from '../hit/hit.component';
import './content.style.css';

export const Content =() => (
<div className = 'content'>
    <Hits hitComponent={Hit} />
    </div>
);
```
This code merely houses the imported _hit_ component.

Add this code to the content.style.css file:

```
ul {
  list-style-type: none;
  width: 60%;
  margin: 0 auto;
  margin-top: 5%;
  }
  
  li {
  margin: 1em 0;
  }  


  @media screen and (max-width: 600px) {
    ul {
      width: 70%;
      margin-left: 5%;
    }
}
```

-----------------------

Back to the components folder:
Create a folder called _hit_, in it, create two files called: `hit.component.jsx` and `hit.style.css`.

Add the following code to the hit.component.jsx file:

```
import React from 'react';
import './hit.style.css';

export const Hit = ({ hit }) => (
    <div className="hit">
        <div className="title">{hit.name}</div>
        <div className="details">Email: {hit.email}</div>
       <div className="details">Website: {hit.website}</div>
      </div>
      
);

```

----------------------------

In this code - `hits` is used to display the name and email results that will be searched for. 

Add the following code to the `hit.style.css file`:

```
@import url('https://fonts.googleapis.com/css?family=Quicksand&display=swap');

body{
    font-family: 'Quicksand', sans-serif;
    width: 100%;
    margin: 0;
}

.hit {
    background-color: rgb(216, 229, 227);
    border-radius: 5px;
}
  
  .title {
    color: grey;
    font-size: 20px;
    line-height: 3;
    text-align: center;
  }
  
  .details {
      color: grey;
      font-size: 10px;
      text-align: center;
  }

```

The App.js file should be updated using this code:

```
import React, { Component} from 'react';
import './App.css';
import {Search} from './../src/components/search/search.component';

class App extends Component {
    
    render(){
    return (
      <div className="App">
          <p>Random contact card</p>
          <Search />
    </div>
    );
    }
  }


  export default App;
```

The search component is imported and rendered. 

Read more about the components- <a href="https://www.algolia.com/doc/api-reference/widgets/instantsearch/react/">here</a>

------------------------------------------------------------------------

**Now it's time to set it up as a PWA:**

In the Public folder, in the _manifest.json_ file, change the short name and name to `random-contact-card`.

Create a _worker.js_ file in the public folder and add this code:

```
const CACHE_NAME = 'random-contact-card-cache';
const urlsToCache = ['/'];

// Install a service worker
self.addEventListener('install', event => {
  // Perform install steps
  event.waitUntil(
    caches.open(CACHE_NAME).then(cache => cache.addAll(urlsToCache))
  );
});

// Cache and return requests
self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(response => {
      // Cache hit - return response
      if (response) {
        return response;
      }
      return fetch(event.request);
    })
  );
});

// Update a service worker
self.addEventListener('activate', event => {
  const cacheWhitelist = ['random-contact-card-cache'];
  event.waitUntil(
    caches.keys().then(cacheNames =>
      Promise.all(
        cacheNames.map(cacheName => {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      )
    )
  );
});
```

Update the index.html file in the public folder:

Add the `javascript` code to the body to check if the browser supports service workers.

```
<script>
      if ('serviceWorker' in navigator) {
        window.addEventListener('load', function () {
          navigator.serviceWorker.register('worker.js').then(function (registration) {
            console.log('Worker registration successful', registration.scope);
          }, function (err) {
            console.log('Worker registration failed', err);
          }).catch(function (err) {
            console.log(err);
          });
        });
      } else {
        console.log('Service Worker is not supported by browser.');
      }
    </script>
```

--------------------------------------------

Add this code to the head of the index.html:

`<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />`
`<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">` - the react logo is used for this app.

Now, update the _index.js_ from `serviceWorker.unregister()` to `serviceWorker.register()`

----------------------------------

It is all set up. yay.

It is time to run an audit on how far we have gone.

Go to your browser console(I assume your project is running on the localhost already). Click on _audits_, then _generate a report_.

If it is giving an error, relax, it happens when it is the first time.

-------------------------------------------

Let us host it on netlify, which is the simplest ever.

Firstly, push your code to GitHub, then
Create an account on netlify -> sign in/up with git -> choose the project you wish to deploy -> the command should be _npm run build_ and the directory should be _build/_.

When the project is live, try to _generate report_ again. _it is best to be done in incognito mode_

See it in action - <a href="https://codesandbox.io/s/random-contact-card-qchni">codesandbox</a> 
For the code - <a href="https://github.com/funmi5/random-contact-card">github</a>

Thanks, for reading!