Skip to content

D-Tsonev/project-3-client

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GA General Assembly, Software Engineering Immersive

Food-Invy A Fullstack MERN App

Overview

An app that keeps track of users' food inventory by monitoring expiry date, quantity and additional options to share food with other people.

This project has been developed during the General Assembly course, with the goal of designing a full-stack MERN app in 10 days' time.

Members

The Brief

  • One week to plan, build, and test our most advanced project to date with achievable scope and a focus on creating a professional finished product.
  • Make it a full-stack application by making our backend and frontend.
  • Use an Express API to serve our data from a Mongo database.
  • Consume our API with a separate frontend built with React.
  • Be a complete product with multiple relationships and CRUD functionality for multiple models.
  • Implement thoughtful user stories/wireframes for MVP and additional features.
  • Have a visually impressive design.

Deployment

Technologies Used

  • Backend:
    • MongoDB
    • Node.js
    • Express
  • Frontend:
    • JavaScript (ES6)
    • React.js
    • HTML5
    • CSS3 + SASS
    • Bulma
  • Dependencies:
    • Axios
    • React-router-dom
    • React-select
    • JSONWebToken
    • Bcrypt
    • mongoose-unique-validator
  • Development Tools:
    • VS Code
    • Git + GitHub
    • Mapbox
    • Heroku
    • Excalidraw - White boarding
    • Zoom
  • External API:
    • Mapbox

Installation Instructions

  1. Clone repo code from GitHub onto your machine.
  2. Use yarn or npm to install all dependencies from the package.json file.
  3. Start server: yarn start/npm start

General Approach & Planning

The three of us worked together to plan out our Minimum Viable Poduct and used Excalidraw for white boarding.

We divided up the tasks needed to set up the backend and took turns writing seed data to populate the site.

Our backend was done in the first three days of the project and then moved on to assigning React components for each of us to do.

Whiteboarding

Backend

We started by setting up much of the boilerplate backend views/controllers and models together.

Models

We eventually created models for the User, to enable registration and login. Also models for the items themselves as well as the user's inventory items and recipes.

  • User
const userSchema = new mongoose.Schema({
  username: { type: String, required: true, unique: true },
  email: { type: String, required: true, unique: true },
  password: { type: String, required: true, hide: true },
  postalCode: { type: String, required: true },
  city: { type: String, required: true },
  street: { type: String, required: true },
  streetNo: { type: String, required: true },
  country: { type: String, required: true },
  coordinates: {
    type: [String], 
    required: true,
    validate: [
      { validator: (types) => (types.length === 2) }
    ],
  },
  preference: { 
    type: String, 
    required: false, 
    enum: {
      values: ['vegetarian', 'vegan', 'pescetarian'],
      message: '{VALUE} is not supported',
    },
  },
})
  • Item
const itemSchema = new mongoose.Schema({
  name: { type: String, required: true },
  category: { type: String, required: true },
  icon: { type: String, required: true },
})
  • Recipe
const recipeSchema = new mongoose.Schema({
  name: { type: String, required: true },
  timeRequired: { type: String, required: true },
  serves: { type: String, required: true },
  instructionSteps: { type: [String], required: true },
  difficulty: { type: String, required: true },
  image: { type: String, required: true },
  ingredients: [recipeItem],
  preference: { type: String, required: false },
})
  • Inventory Item - Embeded reference data
const InventoryItemSchema = new mongoose.Schema({
  item: { type: mongoose.Schema.ObjectId, ref: 'Item', required: true },
  quantity: { 
    type: Number, 
    required: true,
    validate: [
      { validator: (type) => (type > 0) }
    ], 
  },
  expiryDate: { 
    type: Date, 
    required: true,
  },
  user: { type: mongoose.Schema.ObjectId, ref: 'User', required: true },
  isShared: {
    type: Boolean,
    default: false,
    required: false,
  },
})

Controllers

I was wornking on InvenotryItem controllers. The trickies part was attaching user to the item and showing this later on as personal items inventory.

async function create(req, res, next) {
 // ? attach user to item
 req.body.user = req.currentUser
 // ? attach item to inventoryItem
 const item = await Item.findById(req.params.itemId)
 req.body.item = item
 try {
   const newInventoryItem = await InventoryItem.create(req.body)
   res.status(201).json(newInventoryItem)
 } catch (error) {
   next(error)
 }
}

We created a recipe generator(finder), looping through an array of inventory items(ingredients) and returning recipe suggestions if the user has all ingredients needed in his inventory

async function checkForRecipe(req, res, next) {
  try {
    const currentUserId = req.currentUser._id
    const inventoryItemList = await InventoryItem.find({ user: `${currentUserId}` }).populate('item')
    const recipeList = await Recipe.find()
    let foundPotentialRecipe
    const listOfFoundRecipes = recipeList.filter(recipe => {
      for (let index = 0; index < recipe.ingredients.length; index++) {
        if (
          (inventoryItemList.find(inventoryItem => inventoryItem.item.name.toLowerCase() === recipe.ingredients[index].name.toLowerCase())) === undefined
        ) {
          foundPotentialRecipe = false
          break
        } else {
          foundPotentialRecipe = true
        }
      }
      return foundPotentialRecipe

    })

Once all the models were in place, me and another member of the team were tasked with seeding data for the database and adding them using Javascript Object notation which would then be stored as a JSON document on our MongoDB database.

Frontend

After seeding the data, we were ready to move onto the React frontend. While my group worked on the recipe, inventory and the shared food pages I took on the opportunity to build out the register, login and home pages together with the nav bar, a crucial aspect to catch the eye of our users when they land on the site.

  • Home Page

  • Register and Login Page

React Hooks were used for both forms.

export function useForm(initialFormdata) {
  const [formdata, setFormdata] = React.useState(initialFormdata)
  const [formErrors, setFormErrors] = React.useState(initialFormdata)

  const handleChange = e => {
    setFormdata({ ...formdata, [e.target.name]: e.target.value })
    setFormErrors({ ...formErrors, [e.target.name]: '' })
  }

  return {
    formdata,
    formErrors,
    handleChange,
    setFormErrors,
    setFormdata,
  }
}
  • Login page
function Login () {
  const history = useHistory()
  const [isError, setIsError] = React.useState(false)
  const { formdata, handleChange } = useForm({
    email: '',
    password: '',
  })

  const handleSubmit = async (e) => {
    e.preventDefault()

    try {
      const res = await login(formdata)
      setToken(res.data.token)
      history.push('/items')
    } catch (err) {
      setIsError(true)
    }
  }

  const handleFocus = () => {
    setIsError(false)
  }
  • Register Page
function Register() {
  const history = useHistory()
  const { formdata, formErrors, handleChange, setFormErrors } = useForm({
    username: '',
    email: '',
    password: '',
    passwordConfirmation: '',
    postalCode: '',
    city: '',
    street: '',
    streetNo: '',
    country: '',
    preference: '',
    coordinates: '',
  })
  
  const handleSubmit = async (e) => {
    e.preventDefault()

    try {
      await register(formdata)
      history.push('/login')
    } catch (err) {

      setFormErrors(err.response.data.errors)

Wins

This project was one of my favourites where I had the opportunity to learn so much. I loved working with React and MongoDB.

Teamwork: We got on very well, had a good workflow and managed to reach our MVP in time. We were able to support each other and work together towards resolving any issues we ran into.

I struggled with implementing personal inventory on the back end, but I am very pleased with setting this.

I learned how to work on a team project with Github also I was able to help other teammates with their git issues like merge branches, conflicts, git push.

Challenges

This has been the first project I built in a team, using Git and GitHub.

This has been the first time working on top code written by someone else.

One of our biggest challenges has been embedded data and authorization tokens.

Overall I enjoyed working on this project and working in a well organised team.

Future Features

  • Create a Notification feature for expiring food.

Key Learnings

This project taught me a lot, especially about teamwork while coding. Overall I learned more doing this project than I had ever done before, it was by far the largest and most complicated project I have ever undertaken.

One of the most crucial aspects I learnt from this project was the planning. To my disadvantage, I hadn't spent too much time planning on Projects 1 & 2 but here we made a concerted effort not to begin with any coding until we were happy with our plan.

One aspect I think our group could have improved on was asking each other for help sooner. Occasionally we would spend too long on a task without asking for help, losing valuable time, when a group member could have helped out with added knowledge.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 95.9%
  • SCSS 2.3%
  • HTML 1.8%