Skip to content

Frontend Design

Framework used: React Vite

Component Documentation

The frontend has components setup for the developer to use for their pages, This section is dedicated to documenting those components

Notebook.tsx Documentation

location: client/src/components/Notebook.jsx

The Notebook component simulates a flip-book style UI for content you wish to display to the user. It will display two react components at a time, inside the notebook pages (each page sharing the screen space width wise). Any additional react components will be accessible through a pagination bar under the notebook.

Using Notebook.tsx

Notebook accepts the following 4 props: - componentList - Required prop. - JSON object array (continue reading for structure) - Array of page objects to display in the notebook. - parentPageNumber - Optional prop. - Number - Tells notebook the exact page number that the first component in componentList belongs to. - Defaults to 1. - requestNewPage - Optional prop. - Function (continue reading for structure) - A function that fires when a user tries to navigate to a page that doesn’t exist yet. - componentCount - Optional prop. - Number - Tells the notebook how many components exist, even if not all of them appear inside componentList. - Defaults to size of componentList

Note: looking at the naming conventions, you may notice that some props reference pages and others reference components, a page is just a set of 2 components. So the 5th and 6th components should be displayed on page 3.

componentList Structure

ComponentList is an array of JSON objects. Two of these objects make up a single page. Each object consists of two fields: - content: the react component that will be displayed on the notebook page - props: an object containing the props being passed to the content component (field name is what the content component reads the prop as)

requestNewPage Structure

This is a function that accepts one numerical prop. When the Notebook tries to display a page that it doesn't currently have access to the components for (like trying to display components 5 and 6 when only having access to 4 components) this function will be called, passing the page trying to be accessed as a numerical value prop. Its then this functions job to figure out how to handle accessing the page that's not currently accessible.

Example Code

Some sample code for creating a paginated list while utilizing Notebook.jsx:

Note: in this example RecipePreview.jsx is a regular react component that takes a recipe as a prop

import React, { useEffect, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import Notebook from '../components/Notebook';
import PageComponentObject from '../interfaces/PageComponentObject';
import RecipePreview from '../components/notebookPages/RecipePreview';

export default function Home() {
   const [searchParams, setSearchParams] = useSearchParams();
   const pageNumber: number = Number(searchParams.get('pageNumber')) || 1;

   const [componentList, setComponentList] = useState<PageComponentObject[]>([]);
   const [componentCount, setComponentCount] = useState<number>(0);

   // handle fetching page contents
   function handlePageChange(newPage: number) {

      // update the url to have the new page number
      const newParam = new URLSearchParams(searchParams.toString());
      newParam.set('pageNumber', newPage.toString());
      setSearchParams(newParam);

      // empty the componentList so the page does not look frozen to user
      setComponentList([]);

      //send a request to the server for 2 new items, based on newPage value
      axios({method: 'get', url: `recipe/find?limit=2&skip=${((newPage - 1) * 2)}&count=true`})
      .then((response) => {
         // make sure enough entries exist in the database to display requested page
         const maxPages = Math.round(((response.count + 1) / 2) + 1);
         if (maxPages >= newPage) {
            // add each recipe to a component list
            let newComponentList: PageComponentObject[] = [];
            response.recipeObjectArray.forEach((recipe) => {
               newComponentList.push({
                  content: RecipePreview,
                  props: {
                     recipe
                  }
               })
            });
            setComponentList(newComponentList);
            setComponentCount(response.count);
         }
         // if page being requested is too large to be accessible, return a page that isn't
         else { handlePageChange(maxPages) }
      });
   }

   return <Notebook componentList={componentList} parentPageNumber={pageNumber} requestNewPage={handlePageChange} componentCount={componentCount}/>
}