{"id":19435774,"url":"https://github.com/tigeryant/sei-project-three-fe","last_synced_at":"2026-05-17T19:33:14.235Z","repository":{"id":127747876,"uuid":"444452674","full_name":"tigeryant/sei-project-three-fe","owner":"tigeryant","description":"KetoKitchen front end - General Assembly software engineering project","archived":false,"fork":false,"pushed_at":"2022-02-21T16:36:30.000Z","size":2768,"stargazers_count":0,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-07T21:11:37.951Z","etag":null,"topics":["front-end","mern","react","sei"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tigeryant.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-04T14:37:13.000Z","updated_at":"2022-01-30T20:23:24.000Z","dependencies_parsed_at":null,"dependency_job_id":"e05f71e3-8e41-4ced-9b0e-debe67bc03ea","html_url":"https://github.com/tigeryant/sei-project-three-fe","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tigeryant%2Fsei-project-three-fe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tigeryant%2Fsei-project-three-fe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tigeryant%2Fsei-project-three-fe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tigeryant%2Fsei-project-three-fe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tigeryant","download_url":"https://codeload.github.com/tigeryant/sei-project-three-fe/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240619431,"owners_count":19830204,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["front-end","mern","react","sei"],"created_at":"2024-11-10T15:07:57.955Z","updated_at":"2026-05-17T19:33:09.212Z","avatar_url":"https://github.com/tigeryant.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Overview\nI worked in a group with [aromiafolabi](https://github.com/aromiafolabi), [sallyali7](https://github.com/sallyali7) and [astounded2006](https://github.com/astounded2006) to complete this project as part of the General Assembly Software Engineering Immersive course. The course was split into four modules, and this was our submission for module three. During module three, we learnt about Node, Express and Mongo. This was my first exposure to server-side software and databases. The finished project was deployed with Netlify (front end) and Heroku (back end), and can be found [here](https://ketokitchen-proj-three-sei.netlify.app/). This is the front end repository. The back end can be found [here](https://github.com/tigeryant/sei-project-three-be).\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://i.imgur.com/uAXHDqI.png\" width=\"700\"\u003e\n  \u003c/p\u003e\n\n## Brief\nOur task was to build a full stack web application using the MERN stack (Mongo, Express, React and Node).\n\n## Timeframe\nWe were given one week to complete this project.\n\n## Technologies used\n* Express.js\n* Node.js\n* React.js\n* Mongo\n* Mongoose\n* JavaScript\n* Sass\n* Bootstrap\n* Bcrypt\n* JSON Web Tokens\n* Axios\n* Cloudinary\n* Git\n* GitHub\n\n## Approach\nWe decided to build a keto recipe website which we gave the name ‘KetoKitchen’.\n\n## Planning\nOn the first day, we spent our time brainstorming ideas for our app. Ultimately we agreed to design and build KetoKitchen. We decided on a few key features for our minimum viable product (MVP), and then set out some ’stretch goals’ - features that we could work on upon completion of the MVP. We decided that the MVP should include the following pages and functionality: a landing page, an index page - for displaying the recipes, searching and filtering, a show page for each recipe - to display information specific to that recipe, login and registration (authentication), a profile page - to display user data and footer pages - such as an ‘About’ page. Our stretch goals were a favourites feature and a comments feature. One of my team members used Excalidraw to produce the home page wireframe and I drew one for the Index page.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://i.imgur.com/wuLX6Cn.png\" width=\"500\"\u003e\n  \u003cimg src=\"https://i.imgur.com/TTwzGKS.png\" width=\"500\"\u003e\n  \u003c/p\u003e\n\nWe held daily stand ups throughout the week to discuss what each of us were working on and any upcoming tasks that needed to be completed.\n\n## Work split\nFor the first few days, we all worked together on the most fundamental parts of the application so that we had a basic skeleton for the app. An example of this was each writing JSON data in the seeds file to populate the database. After a few days, once this was built, we branched off and took a more modular approach, with each of us working on a separate component or task. My main role at this point was to work on user authentication and, following this, the favourites feature. This involved both front and back end development.\n\n## Build\n### User Authentication\nThe feature I initially worked to implement was user authentication. This involved development on both the front and back end. I wrote the code for the `Register.js` and `Login.js` files. Each of these allows the user to fill in a form which is then submitted via an API call to the back end. Here are some snippets showing the ‘submit’ functions:\n\n```javascript\nconst handleSubmit = async e =\u003e {\n    e.preventDefault()\n    try {\n      const res = await loginUser(formData)\n      setId(res.data._id)\n      setToken(res.data.token)\n      setIsAuth(true)\n      history.push('/recipes')\n    } catch (err) {\n      setIsError(true)\n    }\n  }\n```\n```javascript\nconst handleSubmit = async e =\u003e {\n    e.preventDefault()\n    try {\n      await registerUser(formData)\n      history.push('/login')\n    } catch (err) {\n      setFormErrors(err.response.data.errors)\n    }\n  }\n```\n\nIn order to allow the users to have a display photo, I used a third party image hosting service called Cloudinary. The `handleImageUpload` function can be seen here:\n\n```javascript\nconst handleImageUpload = async (e) =\u003e {\n    const data = new FormData()\n    data.append('file', e.target.files[0])\n    data.append('upload_preset', process.env.REACT_APP_CLOUDINARY_UPLOAD_PRESET)\n    setIsUploadingImage(true)\n    const res = await axios.post(process.env.REACT_APP_CLOUDINARY_URL, data)\n    setFormData({ ...formData, profileImage: res.data.url })\n    setIsUploadingImage(false)\n}\n```\n\nOn the back end I set up routing for login and registration, and wrote the following controllers to handle authentication requests. JSON web tokens were used for the authentication process.\n\n```javascript\nasync function registerUser(req, res, next) {\n  try {\n    const createdUser = await User.create(req.body)\n    return res.status(201).json({\n      message: `Welcome ${createdUser.username}`,\n    })\n  } catch (err) {\n    next(err)\n  }\n}\n \nasync function loginUser(req, res, next) {\n  try {\n    const userToLogin = await User.findOne({ email: req.body.email })\n    if (!userToLogin || !userToLogin.validatePassword(req.body.password)) {\n      throw new Unauthorized()\n    }\n    const token = jwt.sign({ sub: userToLogin._id }, secret, { expiresIn: '7 days' })\n    return res.status(202).json({\n      message: `Welcome Back ${userToLogin.username}`,\n      token,\n      _id: userToLogin._id,\n      userInfo: userToLogin,\n    })\n  } catch (err) {\n    next(err)\n  }\n}\n```\n\n### Favourites feature - front end and back end\nAfter successfully implementing user authentication, I moved on to implementing the favourites feature. This also involved both front and back end development, but my primary focus was on the back end. The favourites feature allows users to ‘favourite’ a particular recipe from the show page - the recipe is then added to their ‘favourites’ list. This process uses Mongoose to query and update the database. When the user views their profile page, the favourites are displayed. Here is the controller I built to handle the request that toggles the recipe. The schema also had to be updated to implement this feature.\n\n```javascript\nasync function toggleFavourite(req, res, next) {\n  const { recipeId } = req.params\n  const { currentUser, currentUserId } = req\n  try {\n    const recipeToFavourite = await Recipe.findById(recipeId).populate('favouritedBy')\n    if (!recipeToFavourite) {\n      throw new NotFound()\n    }\n    if (recipeToFavourite.favouritedBy.find(user =\u003e currentUserId.equals(user._id))) {\n      recipeToFavourite.favouritedBy.remove(currentUserId)\n    } else {\n      recipeToFavourite.favouritedBy.push(currentUser)\n    }\n    await recipeToFavourite.save()\n    return res.status(201).json(recipeToFavourite)\n  } catch (err) {\n    next(err)\n  }\n}\n```\n\nIf the user has not yet favourited the recipe, their id is added to the `favouritedBy` list on the recipe document. If the user has already favourited the recipe, their id is removed. This conditional enables the ‘toggle’ function, meaning a single controller can be used for both adding and removing favourites.\n \nAnother important part of the favourites feature I built was the `getFavourites` controller. When the user visits their profile page, an API call is made which retrieves data about all the recipes they have favourited.\n\n```javascript\nasync function getFavourites(req, res, next) {\n  try {\n    const { userId } = req.params\n    const user = await User.findById(userId).populate('favouriteRecipes')\n    const favouriteRecipes = user.favouriteRecipes\n    return res.status(200).json(favouriteRecipes)\n  } catch (err) {\n    next(err)\n  }\n}\n```\nOn the front end, in the `Profile.js` component, I used the React useEffect hook to make an API call to retrieve the data.\n\n```javascript\nReact,useEffect(() =\u003e {\n    const getData = async () =\u003e {\n      try { \n        const id = getId()\n        const res = await getFavourites(id)\n        console.log('successful response')\n        console.log('res.data: ', res.data)\n        setFavourites(res.data)\n      } catch (err) {\n        console.log('getting favourites info error')\n      }\n    }\n    getData()\n  }, [])\n```\n\n## Known bugs\nOne bug we are aware of is to do with the favourites feature. One of my group members realised that if the user favourites a recipe on the show page, then moves to another page, and then returns to the show page, the favourites button will still display its ‘unfavourited’ state. This is due to a problem with the default state of the ‘isFavourited’ variable.\n\n## Challenges\nOne of the biggest challenges we had was version control. While we had all used Git before, this was the first time we had used it extensively to collaborate and manage five versions of the codebase simultaneously. At times we struggled with merge conflicts and divergent branches. I realised that my own knowledge of Git was not sufficient for the collaborative nature of the project. Due to this, I decided to learn more about Git in my own time. In particular, I tried to develop my understanding of how branches diverge and converge, how stashing works, the relationship between the working tree, the staging tree and the current branch, how changes can be undone to return to a previous state, rebasing vs merging and how conflicts can be resolved. This paid off, as later in the week I was able to help other group members with resolving conflicts and managing branches.\n\n## Key learnings\nOf all the projects at GA, this one taught me the most. In terms of soft skills, I learnt a lot about collaboration in a development team and I got to practise working to a deadline. In terms of tech skills, I learnt a great deal about Git, which I mentioned above, React, and perhaps most intimately, Express. This was the first time I really got to grips with how schemas, routing, middleware and databases work. I spent a lot of time building schemas and middleware, learning about API calls and reading documentation. This experience was truly invaluable and serves as a good reminder of the benefits of active over passive learning.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftigeryant%2Fsei-project-three-fe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftigeryant%2Fsei-project-three-fe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftigeryant%2Fsei-project-three-fe/lists"}