Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rendering update #8

Merged
merged 8 commits into from
May 9, 2022
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions client/src/components/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ const App = (props) => {
return (
<Router>
<TopBar user={currentUser} />
<Route path="/">
<h1>Trip</h1>
</Route>
br-ndt marked this conversation as resolved.
Show resolved Hide resolved
<Switch>
<Route exact path="/">
<h2>Hello from react</h2>
<Route exact path="/users/new" component={RegistrationForm} />
<Route exact path="/user-sessions/new" component={SignInForm} />
<Route exact path="/attractions" component={AttractionsList} />
Expand Down
20 changes: 15 additions & 5 deletions client/src/components/AttractionShowPage.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { useState, useEffect } from "react";

import ReviewTile from "./ReviewTile.js";

import NewReviewForm from "./NewReviewForm.js";
import translateServerErrors from "../services/translateServerErrors.js";

const AttractionShowPage = (props) => {
Expand Down Expand Up @@ -30,6 +29,10 @@ const AttractionShowPage = (props) => {
}
};

const addNewReview = (review) => {
setAttraction({...attraction, reviews: [...attraction.reviews, review]});
}
br-ndt marked this conversation as resolved.
Show resolved Hide resolved

useEffect(() => {
getAttraction();
}, []);
Expand All @@ -38,11 +41,18 @@ const AttractionShowPage = (props) => {
return <ReviewTile key={reviewObject.id} {...reviewObject} />;
});

const attractionName = attraction.name || "Launch Academy";
const attractionDescription = attraction.description || "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
br-ndt marked this conversation as resolved.
Show resolved Hide resolved

return (
<div className="callout">
<h1>{attraction.name}</h1>
<h2>{attraction.description}</h2>
<h4>Attraction Reviews:</h4>
<h1>{attractionName}</h1>
<h2>{attractionDescription}</h2>
<div>
<h4>Add a Review</h4>
<NewReviewForm attractionId={id} addNewReview={addNewReview}/>
</div>
br-ndt marked this conversation as resolved.
Show resolved Hide resolved
<h4>{attractionName} Reviews:</h4>
{reviewTiles}
</div>
);
Expand Down
12 changes: 11 additions & 1 deletion client/src/components/AttractionsList.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useState, useEffect } from "react";
import AttractionTile from "./AttractionTile";
import NewAttractionForm from "./NewAttractionForm";

const AttractionsList = (props) => {
const [attractions, setAttractions] = useState([]);
Expand All @@ -19,6 +20,10 @@ const AttractionsList = (props) => {
}
};

const addNewAttraction = (attraction) => {
setAttractions([...attractions, attraction]);
}
br-ndt marked this conversation as resolved.
Show resolved Hide resolved

useEffect(() => {
getAttractions();
}, []);
Expand All @@ -29,7 +34,12 @@ const AttractionsList = (props) => {

return (
<div className="callout">
Attractions

<h3>Add a New Attraction:</h3>
<div>
<NewAttractionForm addNewAttraction={addNewAttraction}/>
</div>
br-ndt marked this conversation as resolved.
Show resolved Hide resolved
<h3>Attractions:</h3>
{attractionTileComponents}
</div>
);
Expand Down
8 changes: 6 additions & 2 deletions client/src/components/NewAttractionForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ const NewAttractionForm = (props) => {
const [newAttraction, setNewAttraction] = useState({
name: "",
description: "",
// placeholder while we work on locationId integration
locationId: 2,
});
br-ndt marked this conversation as resolved.
Show resolved Hide resolved
const [errors, setErrors] = useState([])
const [shouldRedirect, setShouldRedirect] = useState(false);
Expand All @@ -27,13 +29,16 @@ const NewAttractionForm = (props) => {
}
br-ndt marked this conversation as resolved.
Show resolved Hide resolved
throw new Error(`${response.status} (${response.statusText})`);
} else {
setShouldRedirect(true);
//clearForm();
props.addNewAttraction(body.attraction);
br-ndt marked this conversation as resolved.
Show resolved Hide resolved
}
} catch (error) {
console.error(error.message);
}
};



br-ndt marked this conversation as resolved.
Show resolved Hide resolved
const handleInputChange = (event) => {
event.preventDefault();
setNewAttraction({ ...newAttraction, [event.currentTarget.name]: event.currentTarget.value });
Expand All @@ -50,7 +55,6 @@ const NewAttractionForm = (props) => {

nwalberts marked this conversation as resolved.
Show resolved Hide resolved
return (
<div>
<h3>Add a New Attraction</h3>
br-ndt marked this conversation as resolved.
Show resolved Hide resolved
<ErrorList errors={errors}/>
<form className="attraction-form form" onSubmit={handleSubmit}>
<input type="text" name="name" placeholder="The Colosseum" onChange={handleInputChange}/>
br-ndt marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
35 changes: 29 additions & 6 deletions client/src/components/NewReviewForm.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,37 @@
import React, { useState } from "react";

const NewReviewForm = ({ postReview }) => {
const NewReviewForm = (props) => {
const [newReview, setNewReview] = useState({
title: "",
rating: "",
content: "",
userId: 1,// Placeholder value
});
br-ndt marked this conversation as resolved.
Show resolved Hide resolved

const addNewReview = async () => {
const { attractionId } = props;
try {
const response = await fetch(`/api/v1/attractions/${attractionId}/reviews`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(newReview),
});
const body = await response.json();
if (!response.ok) {
if (response.status === 422) {
const newErrors = translateServerErrors(body.errors);
return setErrors(newErrors);
br-ndt marked this conversation as resolved.
Show resolved Hide resolved
}
throw new Error(`${response.status} (${response.statusText})`);
} else {
clearForm();
props.addNewReview(body.review);
}
} catch (error) {
console.error(error.message);
}
};

const handleInputChange = (event) => {
event.preventDefault();
setNewReview({
Expand All @@ -17,28 +42,27 @@ const NewReviewForm = ({ postReview }) => {

const handleSubmit = (event) => {
event.preventDefault();
postReview(newReview);
clearForm();
addNewReview(newReview);
};

const clearForm = () => {
setNewReview({
title: "",
rating: "",
content: "",
userId: 1
br-ndt marked this conversation as resolved.
Show resolved Hide resolved
});
};

return (
<div>
<h1>Add a Review</h1>
<form onSubmit={handleSubmit}>
<label>
Title:
<input type="text" name="title" onChange={handleInputChange} value={newReview.title} />
</label>
<label>
content:
Content:
<textarea
name="content"
onChange={handleInputChange}
Expand All @@ -54,7 +78,6 @@ const NewReviewForm = ({ postReview }) => {
value={newReview.rating}
/>
</label>

<input type="submit" value="Add Review" />
</form>
</div>
Expand Down
7 changes: 5 additions & 2 deletions client/src/components/layout/TopBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@ const TopBar = ({ user }) => {
<div className="top-bar">
<div className="top-bar-left">
<ul className="menu">
<li className="menu-text">App</li>
<li className="icon">
<img src="/favicon.ico" alt=""/>
</li>
<li><Link to="/">Trip</Link></li>
<li>
<Link to="/">Home</Link>
<Link to="/attractions">Attractions</Link>
</li>
</ul>
</div>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@
},
"engines": {
"node": "^14.19",
"yarn": "^1.22.18"
"yarn": "^1.22.17"
nwalberts marked this conversation as resolved.
Show resolved Hide resolved
}
}
13 changes: 2 additions & 11 deletions server/src/db/Seeder.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,17 @@
import { connection } from "../boot.js"
import LocationSeeder from "./seeders/LocationSeeder.js";
import AttractionSeeder from "./seeders/AttractionSeeder.js"

class Seeder {
static async seed() {
// include individual seed commands here
console.log("seeding locations...");
await LocationSeeder.seed();

import { connection } from "../boot.js";
import AttractionSeeder from "./seeders/AttractionSeeder.js";
import ReviewSeeder from "./seeders/ReviewSeeder.js";
import UserSeeder from "./seeders/UserSeeder.js";

class Seeder {
static async seed() {
console.log("seeding locations...");
await LocationSeeder.seed();
console.log("seeding attractions...");
await AttractionSeeder.seed();
console.log("seeding users...");
await UserSeeder.seed();
console.log("seeding users...");
await UserSeeder.seed();
console.log("seeding reviews...");
await ReviewSeeder.seed();
console.log("Done!");
Expand Down
2 changes: 1 addition & 1 deletion server/src/db/seeders/AttractionSeeder.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class AttractionSeeder {
{
name: "Launch Academy",
description: "Coding boot camp",
locationId: 3
locationId: 2
},
];
for (const singleAttractionData of attractionsData) {
Expand Down
6 changes: 0 additions & 6 deletions server/src/db/seeders/LocationSeeder.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,6 @@ class LocationSeeder {
country: "Israel",
description: "Haifa is the third-largest city in Israel—after Jerusalem and Tel Aviv—with a population of 285,316 in 2019. The city of Haifa forms part of the Haifa metropolitan area, the third-most populous metropolitan area in Israel. It is home to the Baháʼí Faith's Baháʼí World Centre, and is a UNESCO World Heritage Site and a destination for Baháʼí pilgrimage."
},
{
city: "Lynn",
province: "Massachusetts",
country: "USA",
description: "Lynn is the 8th largest municipality in Massachusetts and the largest city in Essex County. Situated on the Atlantic Ocean, 3.7 miles (6.0 km) north of the Boston city line at Suffolk Downs, Lynn is part of Greater Boston's urban inner core. Settled by Europeans in 1629, Lynn is the 5th oldest colonial settlement in the Commonwealth. An early industrial center, Lynn was long colloquially referred to as the 'City of Sin', owing to its historical reputation for crime and vice."
},
{
city: "Boston",
province: "Massachusetts",
Expand Down
8 changes: 3 additions & 5 deletions server/src/models/Attraction.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ class Attraction extends Model {
}

static get relationMappings() {
const { Review } = require("./index.js");
const { Location } = require("./index.js");

return {
location: {
relation: Model.BelongsToOneRelation,
Expand All @@ -26,11 +28,7 @@ class Attraction extends Model {
from: "attractions.locationId",
to: "locations.id"
}
}
}
const { Review } = require("./index.js");

return {
},
reviews: {
relation: Model.HasManyRelation,
modelClass: Review,
Expand Down
7 changes: 1 addition & 6 deletions server/src/models/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@
const Attraction = require("./Attraction.js");
const Location = require("./Location.js");
const User = require("./User.js");

module.exports = { Attraction, Location, User };

const User = require("./User.js");
const Attraction = require("./Attraction.js");
const Review = require("./Review.js");

module.exports = { Review, Attraction, User };
module.exports = { Attraction, Location, User, Review };
19 changes: 19 additions & 0 deletions server/src/routes/api/v1/attractionReviewsRouter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import express from "express";

import { Review } from "../../../models/index.js";

const attractionReviewsRouter = new express.Router({ mergeParams: true });

attractionReviewsRouter.post("/", async (req, res) => {
const { title, content, rating, userId } = req.body;
const { attractionId } = req.params;

try {
const newReview = await Review.query().insertAndFetch({ title, content, rating, attractionId, userId });
return res.status(201).json({ review: newReview });
} catch (error) {
return res.status(500).json({ errors: error });
}
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

user id should come from your passport session, via req.user, not from the frontend.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is also no ValidationError handling here. You are handling for these types of errors on the frontend, but in this implementation those errors would never be used


export default attractionReviewsRouter;
27 changes: 16 additions & 11 deletions server/src/routes/api/v1/attractionsRouter.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import express from "express";
import objection from "objection"
import objection from "objection";
import { Attraction } from "../../../models/index.js";
import cleanUserInput from "../../../services/cleanUserInput.js";
import { ValidationError } from "objection";
import attractionReviewsRouter from "./attractionReviewsRouter.js";

const attractionsRouter = new express.Router();

attractionsRouter.use("/:attractionId/reviews", attractionReviewsRouter);

attractionsRouter.get("/", async (req, res) => {
try {
const attractions = await Attraction.query();
Expand All @@ -15,11 +19,12 @@ attractionsRouter.get("/", async (req, res) => {
});

attractionsRouter.post("/", async (req, res) => {
const { name, description } = cleanUserInput(req.body);
const { name, description, locationId } = cleanUserInput(req.body);
br-ndt marked this conversation as resolved.
Show resolved Hide resolved
try {
const newAttraction = await Attraction.query().insertAndFetch({ name, description });
const newAttraction = await Attraction.query().insertAndFetch({ name, description, locationId });
return res.status(201).json({ attraction: newAttraction });
} catch (error) {
console.log(error);
br-ndt marked this conversation as resolved.
Show resolved Hide resolved
if (error instanceof ValidationError) {
return res.status(422).json({ errors: error.data });
}
Expand All @@ -28,15 +33,15 @@ attractionsRouter.post("/", async (req, res) => {
});

attractionsRouter.get("/:id", async (req, res) => {
const id = req.params.id
const id = req.params.id;
try {
const attraction = await Attraction.query().findById(id)
attraction.reviews = await attraction.$relatedQuery("reviews")
return res.status(200).json({ attraction })
const attraction = await Attraction.query().findById(id);
attraction.reviews = await attraction.$relatedQuery("reviews");
return res.status(200).json({ attraction });
} catch (error) {
console.log(error)
return res.status(500).json({ errors: error })
console.log(error);
return res.status(500).json({ errors: error });
}
})
});

export default attractionsRouter;
export default attractionsRouter;
2 changes: 1 addition & 1 deletion server/src/routes/clientRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import getClientIndexPath from "../config/getClientIndexPath.js";

const router = new express.Router();

const clientRoutes = ["/", "/locations", "/locations/:id", "/user-sessions/new", "/users/new", "/attractions", "/attractions/new", "/attractions/:id"];
const clientRoutes = ["/", "/locations", "/locations/:id", "/user-sessions/new", "/users/new", "/attractions", "/attractions/:id"];

router.get(clientRoutes, (req, res) => {
res.sendFile(getClientIndexPath());
Expand Down