Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
5b3d855
Update and rename README.md to proposal.md
may-sd Sep 27, 2022
5b9c9e6
Starter code
Feathercrown Oct 3, 2022
2fc7a12
More starter code
Feathercrown Oct 3, 2022
1a23883
convert to react project from template
pjsalisbury Oct 5, 2022
ca0804e
mongo integration and some basic routes added
pjsalisbury Oct 5, 2022
d4c1591
fix sendFile paths
pjsalisbury Oct 5, 2022
e2d3333
Reorganize files, got the .js to import
may-sd Oct 7, 2022
3bee89c
add login. bug: register new user JSON.parse error
may-sd Oct 8, 2022
077e499
Moved middleware code to the top of the server file (needs to be ther…
gyue20 Oct 8, 2022
2f6c45f
fix register to redirect on successful account creation
may-sd Oct 8, 2022
b0dca54
Added Mongoose schemas for all data, added routes, added data retriev…
gyue20 Oct 8, 2022
1e7e325
Merge branch 'main' of github.com:may-s-d/final_project
gyue20 Oct 8, 2022
8a92b02
fixing server changes because I'm dumb
gyue20 Oct 9, 2022
902ae52
Completed logic and basic UI design for feed page. Feed page retrieve…
gyue20 Oct 9, 2022
4ee3447
fixed middleware ordering so that the authentication only kicks in if…
gyue20 Oct 9, 2022
0e4dadd
Add header to main page
may-sd Oct 9, 2022
0d66e3d
Fix server routes, migrated registration to bootstrap
may-sd Oct 10, 2022
1d1dabc
formatting and semicolons
gyue20 Oct 10, 2022
c1b5949
formatting
gyue20 Oct 10, 2022
20e34ab
Merge branch 'main' of github.com:may-s-d/final_project
gyue20 Oct 10, 2022
f79dca6
restoring a console.log statement
gyue20 Oct 10, 2022
9054501
updated add, modify, and delete data routes to use Mongoose
gyue20 Oct 10, 2022
341f7d8
Basic styling on login and registration
may-sd Oct 10, 2022
6d4bddc
Readded server changes
may-sd Oct 10, 2022
5ef050d
add basic client-side routes for recipes
pjsalisbury Oct 10, 2022
18a4a6c
Added searching and sorting components
Feathercrown Oct 10, 2022
821ec42
add page to add new recipes
pjsalisbury Oct 11, 2022
badcad1
fully implement adding recipes
pjsalisbury Oct 11, 2022
d8085f4
parse ingredients as array
pjsalisbury Oct 11, 2022
1a93f5f
remove login+register button on those pages
may-sd Oct 11, 2022
72835a5
logout button added. bug: takes a second to render
may-sd Oct 11, 2022
050caf3
fixes to server routes
gyue20 Oct 12, 2022
ba97ad1
Merge branch 'main' of github.com:may-s-d/final_project
gyue20 Oct 12, 2022
752606e
resolved snowpack issue and App.js header issues
gyue20 Oct 12, 2022
28d7280
no longer sends error 401 when not logged in
may-sd Oct 12, 2022
ecb9f8f
fix login + register appearing before logout rendered
may-sd Oct 12, 2022
8ddb81a
add modify/delete/view routes. Lots of other stuff
pjsalisbury Oct 13, 2022
98c7e9d
Style header, login + registration, fix typo
may-sd Oct 13, 2022
ae58f96
edit package.json to work with glitch
may-sd Oct 13, 2022
1710a9f
Merge branch 'main' of https://github.com/may-s-d/final_project into …
Feathercrown Oct 13, 2022
c91acd9
added "Recipebook | " header to the beginning of each page title for …
gyue20 Oct 13, 2022
3ae6fc6
implemented Add Recipe button for a logged-in user, fixed JS formatti…
gyue20 Oct 13, 2022
3781b93
Merge branch 'main' of github.com:may-s-d/final_project
gyue20 Oct 13, 2022
f43926d
Search and Sort By completed!
Feathercrown Oct 13, 2022
8230745
Tiny fix
Feathercrown Oct 13, 2022
8161b21
Fade out descriptions in feed page
Feathercrown Oct 13, 2022
8d69280
fix login when user doesn't exist
may-sd Oct 13, 2022
ff76ed4
Merge branch 'main' of https://github.com/may-s-d/final_project
may-sd Oct 13, 2022
463972f
Fixed viewing full recipe replacing history entry
Feathercrown Oct 13, 2022
1cf979c
Update README.md
may-sd Oct 13, 2022
5af7687
Fix several bugs and unpolished areas
Feathercrown Oct 13, 2022
75a6eac
Merge branch 'main' of https://github.com/may-s-d/final_project into …
Feathercrown Oct 13, 2022
eb2e250
Update README.md
may-sd Oct 14, 2022
193f6b9
Update README.md
may-sd Oct 14, 2022
3876ba6
Update README.md
may-sd Oct 14, 2022
ddcf57c
Updated readme
Feathercrown Oct 14, 2022
7a98c46
Merge branch 'main' of https://github.com/may-s-d/final_project into …
Feathercrown Oct 14, 2022
4f6ba41
Update README.md
may-sd Oct 14, 2022
4cf8770
Updated technical challenges
Feathercrown Oct 14, 2022
ee08c0a
Merge branch 'main' of https://github.com/may-s-d/final_project into …
Feathercrown Oct 14, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
USER1="pjsalisbury"
PASS="FT2uzoqwY5zTGBoa"
HOST="cluster0.fhcxk9b.mongodb.net"
KEY1="OPI9874htUYNur4767"
KEY2="UEITsuhr78356ETG"

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/**
build/**
63 changes: 21 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,49 +1,28 @@
# Final Project
*Due before the start of class, October 13th (final day of the term)*
## React Recipebook
Group members: Gabriel Buonomano, May Dong, Patrick Salisbury, and Grace Yue.

For your final project, you'll implement a web application that exhibits understanding of the course materials.
This project should provide an opportunity to both be creative and to pursue individual research and learning goals.
https://recipe-page-final-project.glitch.me/

## General description
Your project should consist of a complete Web application, exhibiting facets of the three main sections of the course material:
https://youtu.be/UTyCIOlQeNs

- Static web page content and design. You should have a project that is accessible, easily navigable, and features significant content.
- Dynamic behavior implemented with JavaScript (TypeScript is also allowed if your group wants to explore it).
- Server-side programming *using Node.js*. Typically this will take the form of some sort of persistent data (database), authentication, and possibly server-side computation.
- A video (less than five minutes) where each group member explains some aspect of the project. An easy way to produce this video is for you all the groups members to join a Zoom call that is recorded; each member can share their screen when they discuss the project or one member can "drive" the interface while other members narrate (this second option will probably work better.) The video should be posted on YouTube or some other accessible video hosting service. Make sure your video is less than five minutes, but long enough to successfully explain your project and show it in action. There is no minimum video length.
The goal of this application is to allow users to view recipes posted by other users, as well as publish their own recipes. All recipes are viewable in the feed/homepage, where they can be sorted by recency, prep time, servings, and alphabet order. You can search for keywords in the title as well as filter by author, key words in the description or ingredient list, prep time, and servings (for example: `eggs ingredient:milk servings:3`); quotes allow search terms with spaces, and any number of terms can be used at once. Recipes can be viewed by any user, but in order to edit existing recipes or add new ones, you must register or login. Once logged in, you will be able to edit and delete your own recipes, but not the recipes of others. Recipe search and viewing URLs update to represent the page's state and can be shared with others.

## Project ideation
Excellent projects typically serve someone/some group; for this assignment you need to define your users and stakeholders. I encourage you to identify projects that will have impact, either artistically, politically, or in terms of productivity.
The first four recipes are under `username: patrick` and `password: 123`.

### Deliverables
This application is built using the MERN stack -- MongoDB, Express, React, and Node.js. The frontend is designed using React class components and styled using React Bootstrap. The backend is an Express web server and a MongoDB database (which consists of two collections, one for Users and one for Recipes). In addition, the Express server uses Mongoose schemas to interact with the MongoDB database. Finally, the entire project runs in a Node.js development environment.

#### Form Team (due 9/25)
Students are will work in teams of 3-5 students for the project; teams of two can be approved with the permission of the instructor. Working in teams should help enable you to build a good project in a limited amount of time. Use the `#project-logistics` channel in Discord to pitch ideas for final projects and/or find fellow team members as needed.
Technical challenges encountered during the project include:

Teams must be in place by end of day on Sunday, September 25th. If you have not identified a team at this point, you will be assigned a team. You will be given some class time on Monday to work on your proposal, but please plan on reserving additional time outside of class as needed.

#### Proposal (due 9/27)
Provide an outline of your project direction and the names of associated team members.
The outline should have enough detail so that staff can determine if it meets the minimum expectations, or if it goes too far to be reasonable by the deadline. Please include a general description of a project, and list of key technologies/libraries you plan on using (e.g. React, Three.js, Svelte, TypeScript etc.). Two to four paragraps should provide enough level of detail. Name the file proposal.md and submit a pull request by Tuesday, September 27th at 11:59 PM (end of day). Only one pull request is required per team.

There are no other scheduled checkpoints for your project.

#### Turning in Your Project
Submit a second PR on the final project repo to turn in your app and code. Again, only one pull request per team.

Deploy your app, in the form of a webpage, to Glitch/Heroku/Digital Ocean or some other service; it is critical that the application functions correctly wherever you post it.

The README for your second pull request doesn’t need to be a formal report, but it should contain:

1. A brief description of what you created, and a link to the project itself (two paragraphs of text)
2. Any additional instructions that might be needed to fully use your project (login information etc.)
3. An outline of the technologies you used and how you used them.
4. What challenges you faced in completing the project.
5. What each group member was responsible for designing / developing.
6. A link to your project video.

Think of 1,3, and 4 in particular in a similar vein to the design / tech achievements for A1—A4… make a case for why what you did was challenging and why your implementation deserves a grade of 100%.

## FAQs

- **Can I use XYZ framework?** You can use any web-based frameworks or tools available, but for your server programming you need to use Node.js. Your client-side scripting language should be either JavaScript or TypeScript.
- using Mongoose with MongoDB, which posed challenges with the schema design and modified queries
- several group members had never used React before, making this a new development experience
- we used React class components, where the group's only prior experience with React was with hooks/functional components
- along with the React class components, we also made use of lifecycle methods, including componentDidMount, instead of just trying to fetch data in the last line of the constructor. This is a better, more React-y way of doing things, but it did require us to read through the docs and fully understand the component lifecycle.
- ensuring that recipes could always be edited by their owner, but never edited by anyone else. This involved comparing usernames and checking for login at several points during requests.
- using search queries in the URL for viewing/editing recipes. This proved to be an effective way to communicate which recipe the view/edit pages needed to display, but added complexity to ensure that a user could not use this to force edit recipes that were not their own
- parsing search tokens was a long and multi-step process, especially dealing with quotes, special filters, and differing behavior for different filters (partial substring matching for most fields, exact matching for the username, and treating the prep time and servings as a maximum and a minimum respectively)

Group member responsibilities:
- May: Majority of header (including which buttons to render if a user is logged in or not), login and registration page+backend
- Gabriel: Searching and sorting, bugtesting and bugfixing across the whole application, visual planning for the different pages, error handling and recovery
- Patrick: Created add recipe, view recipe, and edit recipe pages. Created clientside routes for adding, modifying, deleting, and viewing recipes and modified those routes on the server side. Set up MongoDB authentication and environment variables.
- Grace: Wrote the Mongoose schemas, implemented add, edit, & delete recipe server routes in Express/Mongoose. Created the landing page in React, styled it with React Bootstrap, and wrote the fetch requests to populate it with the recipe data. Also wrote the recipes in the database & wrote Mongoose queries to populate the database with mock data for testing.
9 changes: 9 additions & 0 deletions build/_snowpack/pkg/import-map.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"imports": {
"react": "./react.js",
"react-bootstrap": "./react-bootstrap.js",
"react-bootstrap/Button": "./react-bootstrap/Button.js",
"react-bootstrap/Card": "./react-bootstrap/Card.js",
"react-dom": "./react-dom.js"
}
}
3 changes: 3 additions & 0 deletions build/_snowpack/pkg/react-dom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { r as reactDom } from './common/index-8d35ac75.js';
export { r as default } from './common/index-8d35ac75.js';
import './common/index-8120deeb.js';
2 changes: 2 additions & 0 deletions build/_snowpack/pkg/react.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { r as react } from './common/index-8120deeb.js';
export { r as default } from './common/index-8120deeb.js';
17 changes: 17 additions & 0 deletions build/pages/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">

<head>
<title>Recipebook | Homepage</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="../css/style.css">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
</head>

<body>
<div id="app"></div>
<script type="module" src="public/index.js"></script>
</body>

</html>
16 changes: 16 additions & 0 deletions build/pages/login.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">

<head>
<title>Recipebook | Login</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="../css/style.css">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
</head>

<body class="blue-bg">
<script type="module" src="public/login.js"></script>
<div id="page"></div>
</body>

</html>
69 changes: 69 additions & 0 deletions build/public/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React from "../_snowpack/pkg/react.js";
import Button from "../_snowpack/pkg/react-bootstrap/Button.js";
import Card from "../_snowpack/pkg/react-bootstrap/Card.js";
import {Container, Row, Col} from "../_snowpack/pkg/react-bootstrap.js";
import Header from "./header.js";
import SearchAndSort from "./searchAndSort.js";
import Table from "./table.js";
class App extends React.Component {
getUser = async () => {
const user = await fetch("/getUser", {
method: "GET",
headers: {
"Content-Type": "application/json"
}
}).then((response) => {
return response.json();
}).then((data) => {
this.state.user = data.result;
});
return user;
};
sortRecipes(recipes) {
var sort = (new URL(location.href).searchParams.get("sort") || "").toLowerCase();
switch (sort) {
case "recent":
return recipes;
case "preptime":
return recipes.sort((recipe1, recipe2) => +recipe1.prepTime - +recipe2.prepTime);
case "servings":
return recipes.sort((recipe1, recipe2) => +recipe1.numPeople - +recipe2.numPeople);
case "alphabetical":
return recipes.sort((recipe1, recipe2) => recipe1.title.localeCompare(recipe2.title));
default:
return recipes;
}
}
constructor(props) {
super(props);
this.state = {
recipes: [],
user: this.getUser()
};
}
componentDidMount() {
fetch("/recipedata?" + new URLSearchParams({
search: new URL(location.href).searchParams.get("search")
}), {
method: "get",
headers: {
"Content-Type": "application/json"
}
}).then((response) => response.json()).then((res) => {
this.setState({...this.state, recipes: this.sortRecipes([...this.state.recipes, ...res])});
});
}
render() {
return /* @__PURE__ */ React.createElement("div", {
className: "App"
}, /* @__PURE__ */ React.createElement(Header, {
accountButtons: true,
loggedIn: this.state.user != false
}), /* @__PURE__ */ React.createElement(SearchAndSort, null), /* @__PURE__ */ React.createElement("body", {
id: "basic"
}, /* @__PURE__ */ React.createElement(Table, {
items: this.state.recipes
})));
}
}
export default App;
5 changes: 5 additions & 0 deletions build/public/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from "../_snowpack/pkg/react.js";
import ReactDOM from "../_snowpack/pkg/react-dom.js";
import App from "./App.js";
var mountNode = document.getElementById("app");
ReactDOM.render(/* @__PURE__ */ React.createElement(App, null), mountNode);
51 changes: 51 additions & 0 deletions mongooseExample.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Not used anywhere, just a quick example of making 2 users and 2 recipes with Mongoose schemas

async function config() {

const user1 = new User({
username: "test",
password: "pswd",
});
const user2 = new User({
username: "test2",
password: "pswd",
});

const recipe1 = new Recipe({
title: "Iced Coffee",
ingredients: [
"coffee beans",
"ice",
"milk",
"sugar"
],
directions: "Grind 1/4 pound of coffee beans, make hot coffee, then pour over ice and add milk and sugar to taste.",
prepTime: 20,
numPeople: 4,
user: user1 // need to declare the users before the recipes, since the recipes cross-reference the users
});

const recipe2 = new Recipe({
title: "Hot Coffee",
ingredients: [
"coffee beans",
"milk",
"sugar"
],
directions: "Grind the coffee beans, make hot coffee, then and add milk and sugar to taste.",
prepTime: 15,
numPeople: 4,
user: user2
});

await user1.save();
await user2.save();
await recipe1.save();
await recipe2.save();

// then check on results
let tempRecipes = Recipe.find({});
console.log(tempRecipes);
let tempUsers = User.find({});
console.log(tempUsers);
}
Loading