Hello! This is Josh 👋🏼
CALI_COOKING.jpg

The California Times Cooking

The California Times Cooking

Full-Stack Project, 2021 (2 weeks)

React | Ruby on Rails | Javascript | PostgreSQL | HTML/CSS

 

This project is a clone of my holy grail cookbook, The NYT Cooking.

 
 
 

The New York Times Cooking is a digital cookbook platform and cooking guide alike, that helps home cooks discover, save and organize recipes written by its editors. Users can also rate and comment while browsing recipes or curated collections of recipes.

 

Since this was a self-initiated 2-week project that was built from ground up, I decided on 6 key MVPs that captured the essence of the original project:

  1. Search for recipes.

  2. Collect recipes and filter by categories.

  3. Add ingredients to shopping list.

  4. Rate / Comment on recipes.

  5. Browse recipes by author/category/collection.

  6. Authenticate users

Based on this high level structure, I designed the Postgres schema, using an Entity-Relationship Diagram (ERD) centered around Recipes and Users table:

 
Database Schema
 

Sample State

entities: Stores objects and their attributes sent from the server via jBuilder needed to render React components.

ui: Stores boolean values that toggle certain ui components, such as a pop-up, a modal, or a loading screen.

errors: Stores any errors handled by server while being processed by the controller.

session: Stores information about the authenticated user. null when no authenticated user is present.

 
{
  entities: {
    recipes: { < recipe_attr > },
    categories: { < category_attr > }
    collections: { < collection_attr > }
  },
  ui: {
    loading: < boolean >,
    modal: < boolean >
  },
  errors: {
    login: ["Incorrect username/password combination"],
  },
  session: {
    currentUserId: 25
  }
}

Implementation!

 

After carefully planning the database schema, strategizing state management, and planning front/back-end API routes, all I had left to do was to implement these MVP features!

 
 

Search for recipes.

Users can look for specific recipes using the search bar. The text input is used to search through not only recipes themselves, but also the collections it may appear in.

 

To prevent multiple ajax calls…

A “typingTimer” state is declared when NavBar is loaded. Whenever there is a “keyup” event in the search bar, we wait until “typingTimer” reaches “doneTypingInterval” (i.e. 500ms) to make an ajax request for searching the input string.

 
 

Collect recipes and filter by categories.

Logged-in users can save their favorite recipes to their recipe box. These recipes are then categorized and searchable in their recipe box page.

 

Client-side filtering

When users select certain categories inside their recipe box, the list of saved recipes gets updated based on their selection without needing to make an additional request to the server. Thus, the state remains unchanged.

 
 

Add ingredients to shopping list.

Logged-in users can save ingredients from specific recipes to their shopping list. Ingredients can be added, read, updated, and deleted (CRUD).

 

Delete Recipe vs. Delete Ingredient?

Deleting a recipe from user’s shopping list is simple- we can delete the corresponding Shopping instance. Deleting a certain ingredient of a recipe from their shopping list requires an additional attribute for Shopping (i.e. “omitted”) to store an array of ingredients that are not needed.

 
 

Rate/Comment on recipes.

The recipe page displays its average rating. Logged-in users can read/write/update/delete comments.

 

Toggling comment to edit mode

If current user is the author of a comment, they are able to toggle to edit mode where they can update/delete their comment. This mode is stored as a boolean in the Comment component.

 
 

Browse recipes.

Logged-in users can view recipes/curated recipes collections. The recipes can be sorted by author, category, or collection.