DEV Community

Cover image for A Freeform Assignment
Brittany
Brittany

Posted on

A Freeform Assignment

This was originally posted on hashnode

I recently received a challenge to create something using San Francisco's food truck open dataset. It could be anything I want, the goal is just to show some of my skills and share some high-quality code.

The challenge states that the team loves to eat and that they are also a team that loves variety, so they also like to discover new places to eat. For this reason, I think I want to create a web application using React to list all of the Food Trucks by name, address, and food items available. In addition, I would love to create an onClick, that would allow a user to see the location on Google Maps. Based on this information, I know some of the APIs I may need include the following:

  • React (it is a frontend application after all)

  • Google MAPS API

  • Chakra-UI (I always wanted to try this)

  • React Router Dom - I know I will need to route to the google maps page somehow.

Those are just some of my thoughts. As build this freeform project, I will share how I get through each challenge that arises and share the resources that get me through it.

Side note: Ideally, I would want to store my information in a database using Postgresql and use nodejs/express to route through some of the rest API routes. However, due to time constraints, my goal was to upload the CSV file using React and display it.

Uploading the CSV file into React

I used WebStylePress youtube tutorial to upload the CSV file and display it using React. The tutorial guided me to the papaparse module, which made this easier than I expected to display the data. Example below:

import React, { useState, useEffect } from "react";
import Data from "./data/Mobile_Food_Facility_Permit.csv";
import Papa from "papaparse";

  const [isDataLoading, setDataLoading] = React.useState(false);
  const [data, setData] = useState([]);

    const fetchData = async () => {
    const response = await fetch(Data);
    const reader = response.body.getReader();
    const result = await reader.read();
    const decoder = new TextDecoder("utf-8");
    const csvData = decoder.decode(result.value);
    const parsedData = Papa.parse(csvData, {
      header: true,
      skipEmptyLines: true,
    }).data;
    setData(parsedData || []);
    setDataLoading(false);
  };

  useEffect(() => {
    setDataLoading(true);
    fetchData();
  }, []);

  console.log(data);
Enter fullscreen mode Exit fullscreen mode

Adding Pagination

Luckily, I built an application with some pagination before. I was able to use this file to pass in the data, the current page, and the pagesize to render the paginated pages using lodash. Thank goodness for having past projects! ๐ŸŽ‰

Below was the result:

import _ from "lodash";

export function paginate(items, currentPage, pageSize) {
  const startIndex = (currentPage - 1) * pageSize;
  return (
    _(items)
      .slice(startIndex)
      .take(pageSize)
      .value()
  );
}
Enter fullscreen mode Exit fullscreen mode

Added the following to App.js to display the pagination.

 const handlePageChange = (pageNum) => {
    setcurrentPage(pageNum);
  };

  const filtered = data;

  if (data && data.length === 0) return <p> There are no data </p>;

  const paginatedTrucks = paginate(data, currentPage, pageSize);

  return (
    <div className="App">
        <Container maxW="2xl" bg="blue.600" centerContent>
          <h1> Showing {data.length} Food Trucks in database.</h1>
          <TableContainer>
            <Table variant="simple" overflow="scroll" size="sm" maxWidth="10">
              <TableCaption>
                <Pagination
                  itemsCount={filtered.length}
                  pageSize={pageSize}
                  onPageChange={handlePageChange}
                  currentPage={currentPage}
                />
              </TableCaption>
              <Thead>
                <Tr>
                  <Th>Name</Th>
                </Tr>
              </Thead>
              <Tbody>
                {paginatedTrucks.length !== 0 &&
                  paginatedTrucks.map((row, index) => (
                    <Tr>
                      <Td >
                        {row.Applicant}
                      </Td>
                    </Tr>
                  ))}
              </Tbody>
            </Table>
          </TableContainer>
        </Container>
    </div>
Enter fullscreen mode Exit fullscreen mode

Adding a Search Bar

This was by far the hardest part and took me a while to get. The goal was to allow a user to filter through the names of this application to show the Name, FoodItems, and Location. I struggled because the data was an array of multiple objects. For some reason, I could not wrap my mind around how I could filter through the data["Applicant"] and find the value that matched the search query.

First Attempt

I know had to use Object.values and Object.keys to map through the objects in the array to display in the table. I ended up with this solution, which did show the item, but I had to figure out how to show all of them.

  const item = props.trucks[0];
  console.log(Object.keys(item).map((key) => console.log(key)));
Enter fullscreen mode Exit fullscreen mode

Resources used:

FoodTrucks.jsx

import React from "react";
export default function FoodTrucks(props) {
  return (
    <>
      {props.trucks.length ? (
        <table className="table">
          <thead>
            <tr>
              {Object.keys(item).map((key) => (
                <th key={key}>{key}</th>
              ))}
            </tr>
          </thead>
          <tbody>
            {props.trucks.map((row, index) => (
              <tr key={index}>
                {Object.values(row).map((key) => (
                  <th key={key}>{key}</th>
                ))}
              </tr>
            ))}
          </tbody>
        </table>
      ) : null}
    </>
  );
}
  return (
    <>
      {props.trucks.length ? (
        <table className="table">
          <thead>
            <tr>
              {Object.keys(item).map((key) => (
                <th key={key}>{key}</th>
              ))}
            </tr>
          </thead>
          <tbody>
            {props.trucks.map((row, index) => (
              <tr key={index}>
                {Object.values(row).map((key) => (
                  <th key={key}>{key}</th>
                ))}
              </tr>
            ))}
          </tbody>
        </table>
      ) : null}
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

I searched all over the web and eventually figured out the answer by using lodash again. I was able to use the .map to get the value for each object and check to see if it matched the searchQuery a user input. Then the lodash.map allows us to pass in a callback function to return the results from the filter. This was the result:

  const Search = (searchTerm, limit = 10) => {
    let results = [];
    _.map(data, function filterItem(n) {
      if (n.Applicant.toLowerCase().startsWith(searchTerm.toLowerCase())) {
        results.push(n);
      }
    });
    return results;
  };
Enter fullscreen mode Exit fullscreen mode

I am so happy I figured that out!!!! ๐Ÿคฃ๐ŸŽ‰

Google Maps

At this point, I have been working on this project for 4 hours, which is a bit longer than I wanted. So I used some resources to get a move on. I used the following youtube video and honestly, copied the code and pasted it into my project. (If anything I am resourceful, shout out to @mafiacodes on Youtube, make sure you subscribe to their channel!!

The goal was to take Google Maps and when a user clicks on the location, it will route them to the map with the location there. For this, I needed to add Google Maps API / React Google Maps Api Style Guide, of course, but also React router dom to show this on a different page.

Issues

I ran into an issue with my Marker not showing up on the Google Map. I googled around and found out that it is a known issue and some believe it has to do with React.StrictMode. I ended up importing the MarkerF "@react-google-maps/api" and that appeared to work. I will do more research on why this error occurred, but for now, it will have to do, due to. . .you guessed it. . .time constraints.

Here are the links to the resources I used to resolve the issue:

Styling:

I wanted to try a new library but also easily be able to update styling so I went with chakra-ui. It was fun to mess around with it for this project. I would love to do more with

Updating my readme:

I wanted to make sure my readme was ๐Ÿ”ฅ, so I used my favorite readme template and used this markdown playground to make sure everything was to my liking.

End Credits

As I said at the beginning of this post, this was simply to get something done in 2-4 hours, ideally, I would want to have a backend using nodejs and SQL as a database. I may attempt this on my own time, just to show how I would go about it or maybe I will try to rebuild it using nextjs-prisma-postgres because why not?!?!? haha

Let me know if you would like to see the Github link.

I hope you enjoyed this read and as always I leave you with a song:

Song of the day:

Laura Roy ยท Sunrise

Top comments (0)