├── server
├── routers
│ ├── api.js
│ ├── posts.js
│ ├── listItems.js
│ └── pets.js
├── models
│ ├── petModel.js
│ └── BucketListModels.js
├── server.js
└── controllers
│ ├── ListItemController.js
│ ├── petController.js
│ └── PostController.js
├── .gitignore
├── README.md
├── client
├── index.js
├── components
│ ├── DisplayPost.jsx
│ ├── UncompletedBucketlistItem.jsx
│ ├── CreateListItem.jsx
│ ├── feed.jsx
│ ├── AddPostForm.jsx
│ ├── Login.jsx
│ ├── Signup.jsx
│ ├── CompletedBucketlistItem.jsx
│ ├── Bucketlist.jsx
│ └── BucketlistItemDisplay.jsx
├── styles.scss
└── App.jsx
├── index.html
├── webpack.config.js
├── LICENSE
└── package.json
/server/routers/api.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # yeti-crab-professionals
--------------------------------------------------------------------------------
/client/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from 'react-dom';
3 | import App from './App.jsx'
4 |
5 | render(
6 | ,
7 | document.getElementById('app')
8 | );
--------------------------------------------------------------------------------
/client/components/DisplayPost.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | function DisplayPost(props) {
4 | return (
5 |
6 |
7 |
8 | )
9 | }
10 |
11 | export default DisplayPost;
--------------------------------------------------------------------------------
/client/styles.scss:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | margin: 0;
4 | padding: 0;
5 | font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
6 | color: black;
7 | }
8 |
9 | .form-container {
10 | width: 100%;
11 | display: flex;
12 | flex-direction: column;
13 | align-items: center;
14 | }
--------------------------------------------------------------------------------
/client/components/UncompletedBucketlistItem.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | function UncompletedBucketlistItem(props) {
4 | return (
5 |
6 |
{props.listItem}
7 | handleCheckedOffClick(props.listItem)} type="checkbox"/>
8 |
9 | )
10 | }
11 |
12 | export default UncompletedBucketlistItem;
--------------------------------------------------------------------------------
/client/components/CreateListItem.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | function CreateListItem(props) {
4 |
5 | return (
6 |
7 | Create New Bucket List Item
8 |
9 |
10 |
11 | )
12 | }
13 |
14 | export default CreateListItem;
--------------------------------------------------------------------------------
/server/routers/posts.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 |
3 | const postController = require('../controllers/PostController');
4 |
5 | const router = express.Router();
6 |
7 | router.post('/', postController.addPost);
8 | router.get('/', postController.getAllPosts);
9 | router.get('/:title', postController.getPost);
10 | router.put('/:title', postController.updatePost);
11 | router.delete('/:title', postController.deletePost);
12 |
13 | module.exports = router;
14 |
--------------------------------------------------------------------------------
/server/models/petModel.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const Schema = mongoose.Schema;
3 |
4 | const petSchema = new Schema({
5 | username: { type: String, required: true },
6 | password: { type: String, required: true },
7 | profilePicture: { type: String, required: true },
8 | age: { type: Number, require: true },
9 | bio: { type: String },
10 | name: { type: String, required: true },
11 | });
12 |
13 | module.exports = mongoose.model("Pet", petSchema);
14 |
--------------------------------------------------------------------------------
/server/routers/listItems.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 |
3 | const listItemController = require('../controllers/ListItemController.js');
4 |
5 | const router = express.Router();
6 |
7 | router.post('/', listItemController.addItem);
8 | router.get('/', listItemController.getAllItems);
9 | router.get('/:item', listItemController.getItem);
10 | router.put('/:item', listItemController.updateItem);
11 | router.delete('/:item', listItemController.deleteItem);
12 |
13 | module.exports = router;
14 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Petrospective
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/server/routers/pets.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const petController = require("../controllers/petController.js");
3 | const router = express.Router();
4 |
5 | //create pet docuemnt and send data back to frontend to map data
6 | router.post("/signup", petController.createPet, (req, res) => {
7 | res.send(200).json(res.locals.pets);
8 | });
9 |
10 | router.get("/login", petController.validateUser);
11 |
12 | router.put("/:username", petController.updatePetBio, (req, res) => {
13 | // CHANGED ALL res.send to res.status
14 | res.status(200).json(res.locals.updatedBio);
15 | });
16 |
17 | router.delete("/:username", petController.deletePet, (req, res) => {
18 | // CHANGED ALL res.send to res.status
19 | res.status(200);
20 | });
21 |
22 | // exported the router
23 | module.exports = router;
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const path = require('path');
3 |
4 | module.exports = {
5 | mode: process.env.NODE_ENV,
6 | entry: './client/index.js',
7 | output: {
8 | path: path.join(__dirname, 'build'),
9 | filename: 'bundle.js'
10 | },
11 |
12 | devServer: {
13 | publicPath: '/build',
14 | proxy: {
15 | '/api/': 'http://localhost:3000'
16 | },
17 | port: 8080
18 | },
19 | module: {
20 | rules: [
21 | {
22 | test: /\.jsx?/,
23 | exclude: /(node_modules)/,
24 | use: [{
25 | loader: 'babel-loader',
26 | options: {
27 | presets: ['@babel/preset-env', '@babel/preset-react']
28 | }
29 | }]
30 | },
31 | {
32 | test: /\.s[ac]ss$/i,
33 | exclude: /(node_modules)/,
34 | use: ['style-loader', 'css-loader', 'sass-loader']
35 | }
36 | ]
37 | }
38 |
39 | };
40 |
41 |
--------------------------------------------------------------------------------
/client/App.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
3 | // import './styles.css';
4 | import Login from "./components/Login.jsx";
5 | // import Home from "./components/Home.jsx";
6 | // import Feed from "./containers/Feed.jsx";
7 | import Signup from "./components/Signup.jsx";
8 | import Bucketlist from './components/Bucketlist.jsx'
9 |
10 |
11 | class App extends Component {
12 | render() {
13 | return (
14 |
15 |
16 | {/* */}
17 |
18 | )
19 | }
20 | }
21 |
22 | export default App;
23 |
24 | //
25 | //
26 | //
27 | //
28 | // {/* */}
29 | //
30 | // 404, dawg
31 | //
32 | //
33 |
--------------------------------------------------------------------------------
/client/components/feed.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
3 |
4 | const Feed = (props) => {
5 |
6 | function renderTable() {
7 | return this.props.something.map((info, index) => {
8 | {listItem, date, postDescription, location, youtubeLink} = info;
9 | return (
10 |
11 |
12 | This is where a header would go
13 |
14 | {listItem}
15 | {date}
16 | {postDescription}
17 | {location}
18 | {`
19 |
20 | )
21 | })
22 | }
23 |
24 | render() {
25 | return (
26 |
27 |
28 |
{this.renderTable()}
29 |
30 |
31 | )
32 | }
33 | }
34 |
35 |
36 |
37 | export default Feed;
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Yeti-Crab-Squad
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/server/models/BucketListModels.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 |
3 | // save the Schema class to a variable so we can use its constructor
4 | const Schema = mongoose.Schema;
5 |
6 | // create schema for bucket list items
7 | const listItemSchema = new Schema({
8 | listItem: { type: String, required: true },
9 | isChecked: { type: Boolean },
10 | hasPost: { type: Boolean },
11 | });
12 |
13 | // create a model that conforms to the schema
14 | const ListItem = mongoose.model('listItem', listItemSchema);
15 |
16 | // create schema for bucket list posts
17 | const postSchema = new Schema({
18 | listItem: { type: String, required: true },
19 | datePosted: { type: String, required: true },
20 | dateCompleted: { type: String, required: true },
21 | postDescription: { type: String, required: true },
22 | location: { type: String, required: true },
23 | // is the above a Google Maps URL or a string that tells Maps to make a map?
24 | youtubeLink: String,
25 | images: Array,
26 | });
27 |
28 | // create a model that conforms to the schema
29 | const Post = mongoose.model('post', postSchema);
30 |
31 | module.exports = {
32 | ListItem,
33 | Post,
34 | };
35 |
--------------------------------------------------------------------------------
/client/components/AddPostForm.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | function AddPostForm(props) {
4 | return (
5 |
6 | {/* research ways to formalize Date input data */}
7 | Date Completed:
8 |
9 | Post Body:
10 |
11 | Youtube Link
12 |
13 | Google Map Link
14 |
15 | Add Images
16 |
17 | Add New Image
18 | Submit Post!
19 |
20 | )
21 | }
22 |
23 |
24 | export default AddPostForm;
--------------------------------------------------------------------------------
/client/components/Login.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Redirect } from "react-router-dom";
3 | import { Link } from "react-router-dom";
4 |
5 | class Login extends Component {
6 | constructor() {
7 | super();
8 | this.state = {
9 | loggedIn: false,
10 | failedLogin: false,
11 | };
12 |
13 | // this.validate = this.validate.bind(this);
14 | }
15 |
16 | render() {
17 | // if (this.state.loggedIn) {
18 | // return ;
19 | // }
20 |
21 | return (
22 |
23 |
Welcome !
24 |
42 |
43 | );
44 | }
45 | }
46 |
47 | export default Login;
48 |
--------------------------------------------------------------------------------
/client/components/Signup.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Redirect } from "react-router-dom";
3 | import { Link } from "react-router-dom";
4 |
5 | class Signup extends Component {
6 | constructor() {
7 | super();
8 | this.state = {
9 | loggedIn: false,
10 | failedLogin: false,
11 | };
12 |
13 | // this.validate = this.validate.bind(this);
14 | }
15 |
16 | render() {
17 | // if (this.state.loggedIn) {
18 | // return ;
19 | // }
20 |
21 | return (
22 |
23 |
Welcome !
24 |
47 |
48 | );
49 | }
50 | }
51 |
52 | export default Signup;
53 |
--------------------------------------------------------------------------------
/client/components/CompletedBucketlistItem.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | function CompletedBucketlistItem(props) {
4 | const [displayPost, setDisplayPost] = useState(false)
5 | const [postData, setPostData] = useState()
6 |
7 | function showPost(listItem) {
8 | fetch(`/api/posts/${listItem}`)
9 | .then(res => res.json())
10 | .then(data => {
11 | setDisplayPost(true)
12 | setPostData(data)
13 | })
14 | }
15 |
16 | if (!displayPost) {
17 | return (
18 |
19 |
20 |
{props.listItem}
21 | {props.dateCompleted}
22 | showPost(props.listItem)}>See Post
23 |
24 |
25 |
26 | )
27 | } else {
28 | return (
29 |
30 |
{postData.listItem}
31 |
{postData.date}
32 |
{postData.postDescription}
33 | {postData.images.map(image => {
34 | return
35 | })}
36 |
37 |
38 |
39 | )
40 | }
41 |
42 |
43 |
44 |
45 | }
46 |
47 | export default CompletedBucketlistItem;
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "petrospective",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "jest --verbose",
8 | "start": "nodemon server/server.js",
9 | "build": "NODE_ENV=production webpack",
10 | "dev": "NODE_ENV=development webpack-dev-server & nodemon server/server.js --open"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/andrew-lovato/petrospective.git"
15 | },
16 | "author": "",
17 | "license": "ISC",
18 | "bugs": {
19 | "url": "https://github.com/andrew-lovato/petrospective/issues"
20 | },
21 | "homepage": "https://github.com/andrew-lovato/petrospective#readme",
22 | "dependencies": {
23 | "bcrypt": "^5.0.0",
24 | "cors": "^2.8.5",
25 | "enzyme": "^3.11.0",
26 | "express": "^4.17.1",
27 | "mongoose": "^5.10.7",
28 | "oauth": "^0.9.15",
29 | "react": "^16.13.1",
30 | "react-dom": "^16.13.1",
31 | "react-router": "^5.2.0",
32 | "react-router-dom": "^5.2.0"
33 | },
34 | "devDependencies": {
35 | "@babel/core": "^7.11.6",
36 | "@babel/preset-env": "^7.11.5",
37 | "@babel/preset-react": "^7.10.4",
38 | "babel-loader": "^8.1.0",
39 | "css-loader": "^4.3.0",
40 | "fs": "0.0.1-security",
41 | "path": "^0.12.7",
42 | "sass-loader": "^10.0.2",
43 | "style-loader": "^1.3.0",
44 | "webpack": "^4.44.2",
45 | "webpack-cli": "^3.3.12",
46 | "webpack-dev-server": "^3.11.0"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/client/components/Bucketlist.jsx:
--------------------------------------------------------------------------------
1 | // import React, { useState, useEffect } from 'react';
2 | // import BucketlistItemDisplay from './BucketlistItemDisplay.jsx'
3 | // import CreateListItem from './CreateListItem.jsx'
4 |
5 | // function Bucketlist(props) {
6 | // const [bucketlistItems, setBucketlistItems] = useState([]);
7 | // const [newItem, setNewItem] = useState()
8 |
9 | // useEffect(() => {
10 | // fetch('/api/listItems')
11 | // .then(res => res.json())
12 | // .then(data => {
13 | // setBucketlistItems(data)
14 | // })
15 | // })
16 |
17 | // function handleNewItemClick() {
18 |
19 | // fetch('/api/listItems', {
20 | // method: 'POST',
21 | // headers: {
22 | // 'Content-Type': 'application/json'
23 | // },
24 | // body: newItem
25 | // })
26 | // .then(res => res.json())
27 | // .then(data => {
28 | // setNewItem('')
29 |
30 | // useEffect(() => {
31 | // fetch('/api/listItems')
32 | // .then(res => res.json())
33 | // .then(data => {
34 | // setBucketlistItems(data)
35 |
36 | // })
37 | // })
38 | // })
39 | // }
40 |
41 | // function handleNewItemChange(e) {
42 | // e.preventDefault()
43 | // let newItem = e.target.value;
44 |
45 | // setNewItem(newItem);
46 | // }
47 |
48 | // return(
49 | //
50 | //
54 | // {bucketlistItems.map(item => {
55 | // return
56 | // })
57 | // }
58 |
59 | //
60 |
61 | // )
62 | // }
63 |
64 | // export default Bucketlist;
--------------------------------------------------------------------------------
/server/server.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const app = express();
3 | const path = require("path");
4 | const cors = require("cors");
5 | const PORT = 3000;
6 | const mongoose = require("mongoose");
7 |
8 | const petRouter = require("./routers/pets.js");
9 | const postRouter = require('./routers/posts');
10 | const listItemRouter = require('./routers/listItems');
11 | // uncomment once there is middleware
12 | // const api = require('./routers/api')
13 |
14 | const MONGO_URI =
15 | "mongodb+srv://AndrewL:bucketlist@cluster0.00tox.mongodb.net/?retryWrites=true&w=majority";
16 |
17 | mongoose
18 | .connect(MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
19 | .then(() => console.log("CONNECTED TO MONGO DB"));
20 |
21 | app.use(express.json());
22 | app.use(express.urlencoded({ extended: true }));
23 | app.use(cors()); // remember to npm install cors
24 |
25 | // changed to /api/pet so that it will be routed through the webpack router
26 | // app.use("/pet", petRouter);
27 | app.use("/api/pet", petRouter);
28 | app.use('/api/listItems', listItemRouter);
29 | app.use('/api/posts', postRouter);
30 |
31 | app.get("/", (req, res) => {
32 | res.sendFile(path.join(__dirname, "../index.html"));
33 | });
34 |
35 | // app.post request will trigger controller to Create a New User --> Pushing data to the noSQL database
36 |
37 | // Global error handler for catching middleware errors
38 | app.use((err, req, res, next) => {
39 | const defaultError = {
40 | log: "Error during unknown middleware",
41 | status: 400,
42 | message: { err: "Uh-oh, error time, baby! :)" },
43 | };
44 | const errorObj = Object.assign({}, defaultErr, err);
45 | console.log(errorObj.log);
46 | return res.status(errorObj.status).json(errorObj.message);
47 | });
48 |
49 | // Seed the database
50 | const postSeedDb = {
51 | listItem: 'I want to hike in Central Park with Rocko',
52 | date: 'Jan 7th 2058',
53 | postDescription: "Central Park sure has changed",
54 | youtubeLink: 'fakeYoutubeLink',
55 | location: 'fakeYoutubeLink',
56 | images: ['image1', 'image2']
57 | }
58 |
59 | fetch('/api/posts', {
60 | method: 'POST',
61 | headers: {
62 | 'Content-type': 'application/json'
63 | },
64 | body: postSeedDb
65 | })
66 | .then(res => res.json())
67 | .then(data => {
68 | console.log('Post data was added to the DB')
69 | })
70 | .catch(err =>{
71 | console.log(err)
72 | })
73 |
74 |
75 | app.listen(PORT, () => console.log(`Listening on PORT: ${PORT}.`));
76 |
--------------------------------------------------------------------------------
/server/controllers/ListItemController.js:
--------------------------------------------------------------------------------
1 | const { ListItem } = require('../models/BucketListModels');
2 |
3 | const ListItemController = {
4 | // creates new list items for the bucket list
5 | addItem(req, res, next) {
6 | ListItem.create({
7 | listItem: req.body.listItem,
8 | isChecked: false,
9 | }, (err, newItem) => {
10 | if (err) {
11 | next({
12 | log: 'Error creating list item. Please check middleware syntax.',
13 | });
14 | }
15 | res.locals.items = newItem;
16 | // changed to.json
17 | // res.status(200).send(newItem);
18 | res.status(200).json(newItem);
19 | });
20 | },
21 |
22 | getAllItems(req, res, next) {
23 | ListItem.find({},
24 | (err, allItems) => {
25 | if (err) {
26 | next({
27 | log: 'Error grabbing list items. Please check middleware syntax.',
28 | });
29 | } else {
30 | // setting the value to -1 sorts IDs descending, so posts from newest to oldest
31 | allItems.sort({ _id: -1 });
32 | res.status(200).send(allItems);
33 | }
34 | });
35 | },
36 |
37 | getItem(req, res, next) {
38 | const itemTitle = req.params.item;
39 | ListItem.findOne({ listItem: itemTitle },
40 | (err, foundItem) => {
41 | if (err) {
42 | next({
43 | log: 'Error getting list item. Please check middleware syntax.',
44 | });
45 | } else {
46 | // changed to.json
47 | // res.status(200).send(newItem);
48 | res.status(200).json(foundItem);
49 | }
50 | });
51 | },
52 |
53 | updateItem(req, res, next) {
54 | const itemTitle = req.params.item;
55 | const update = {
56 | listItem: req.body.listItem,
57 | isChecked: req.body.isChecked,
58 | hasPost: req.body.hasPost,
59 | };
60 | ListItem.findOneAndUpdate({ listItem: itemTitle }, update,
61 | (err, updatedItem) => {
62 | if (err) {
63 | next({
64 | log: 'Error updating list item. Please check middleware syntax.',
65 | });
66 | } else {
67 | res.status(200).send(updatedItem);
68 | }
69 | });
70 | },
71 |
72 | // deletes items from the bucket list
73 | deleteItem(req, res, next) {
74 | const itemTitle = req.params.item;
75 | ListItem.deleteOne({
76 | listItem: itemTitle,
77 | }, (err) => {
78 | if (err) {
79 | next({
80 | log: 'Error deleting list item. Please check middleware syntax.',
81 | });
82 | } else {
83 | res.sendStatus(200);
84 | }
85 | });
86 | },
87 | };
88 |
89 | module.exports = ListItemController;
90 |
--------------------------------------------------------------------------------
/server/controllers/petController.js:
--------------------------------------------------------------------------------
1 | const Pet = require("../models/petModel.js");
2 | const PetController = {};
3 | const SALT_WORK_FACTOR = 10;
4 | const bcrypt = require("bcryptjs");
5 |
6 | PetController.createPet = (req, res, next) => {
7 | const { username, password, profilePicture, age, bio, name } = req.body;
8 | bcrypt.hash(password, SALT_WORK_FACTOR, (err, hash) => {
9 | Pet.create(
10 | { username, password: hash, profilePicture, age, bio, name },
11 | (err, pet) => {
12 | if (err) {
13 | return next({
14 | log:
15 | "Error occured in PetController.createPet middleware. Please check your syntax.",
16 | message: { err: err },
17 | });
18 | }
19 | res.locals.pets = pet;
20 | return next();
21 | }
22 | );
23 | });
24 | };
25 |
26 | PetController.validateUser = (req, res, next) => {
27 | const { username, password } = req.params;
28 | Pet.find({ username, password }, (err, user) => {
29 | if (err) {
30 | res.send("please enter a valid username and password.");
31 | return next({
32 | log:
33 | "Error occured in PetController.validateUser middleware. Please check your syntax.",
34 | message: { err: err },
35 | });
36 | }
37 | bcrypt.compare(password, user.password, (err, result) => {
38 | if (result) {
39 | console.log("success!");
40 | //change this redirect name based on the frontend
41 | res.send(200).redirect("/home");
42 | } else {
43 | //change this redirect name based on the frontend
44 | res.send("Incorrect password. Please try again.");
45 | res.send(200).redirect("/");
46 | }
47 | });
48 | });
49 | return next();
50 | };
51 |
52 | PetController.updatePetBio = (req, res, next) => {
53 | // Changed this to access the username, not bio, because was set to username in the initial route
54 | // const { bio } = req.params;
55 | const { username } = req.params
56 | const { updatedBio } = req.body;
57 | Pet.findOneAndUpdate(
58 | // changed to username
59 | // { name: bio },
60 | { name: username},
61 | // changed name to bio
62 | // { name: updatedBio },
63 | { bio: updatedBio },
64 | { new: true },
65 | (err, pet) => {
66 | if (err) {
67 | return next({
68 | log:
69 | "Error occured in PetController.updatePetName middleware. Please check your syntax.",
70 | message: { err: err },
71 | });
72 | }
73 | res.locals.updatedBio = pet;
74 | return next();
75 | }
76 | );
77 | };
78 |
79 | PetController.deletePet = (req, res, next) => {
80 | const { username } = req.params;
81 | Pet.deleteOne({ username: username }, (err, pet) => {
82 | if (err) {
83 | return next({
84 | log:
85 | "Error occured in PetController.deletePet middleware. Please check your syntax.",
86 | message: { err: err },
87 | });
88 | }
89 | return next();
90 | });
91 | };
92 |
93 | module.exports = PetController;
94 |
--------------------------------------------------------------------------------
/server/controllers/PostController.js:
--------------------------------------------------------------------------------
1 | const { Post } = require('../models/BucketListModels');
2 |
3 | const PostController = {
4 | // creates new posts for your feed
5 |
6 | addPost(req, res, next) {
7 |
8 | Post.create({
9 | listItem: req.body.listItem,
10 | date: req.body.date,
11 | postDescription: req.body.postDescription,
12 | location: req.body.location,
13 | // is the above a Google Maps URL or a string that tells Maps to make a map?
14 | youtubeLink: req.body.youtubeLink,
15 | // imageUpload: Come back to this. Use GridFS to store images
16 | }, (err, newPost) => {
17 | if (err) {
18 | next({
19 | log: 'Error creating post. Please check middleware syntax.',
20 | });
21 | } else {
22 | // changed to.json
23 | // res.status(200).send(newPost);
24 | res.status(200).json(newPost);
25 | }
26 | });
27 | },
28 |
29 | getAllPosts(req, res, next) {
30 | Post.find({},
31 | (err, allPosts) => {
32 | if (err) {
33 | next({
34 | log: 'Error grabbing post feed. Please check middleware syntax.',
35 | });
36 | } else {
37 | // setting the value to -1 sorts IDs descending, so posts from newest to oldest
38 | allPosts.sort({ _id: -1 });
39 | res.status(200).send(allPosts);
40 | }
41 | });
42 | },
43 |
44 | // displays posts in database
45 | getPost(req, res, next) {
46 | const postTitle = req.params.title;
47 | Post.findOne({ listItem: postTitle },
48 | (err, foundPost) => {
49 | if (err) {
50 | next({
51 | log: 'Error getting post. Please check middleware syntax.',
52 | });
53 | } else {
54 | // changed to.json
55 | // res.status(200).send(newPost);
56 | res.status(200).json(foundPost);
57 | }
58 | });
59 | },
60 |
61 | // allows you to edit and update posts for your feed
62 | updatePost(req, res, next) {
63 | const postTitle = req.params.title;
64 | const update = {
65 | listItem: req.body.listItem,
66 | datePosted: req.body.datePosted,
67 | dateCompleted: req.body.dateCompleted,
68 | postDescription: req.body.postDescription,
69 | location: req.body.location,
70 | youtubeLink: req.body.youtubeLink,
71 | // imageUpload: req.body.imageUpload,
72 | };
73 | Post.findOneAndUpdate({ listItem: postTitle }, update,
74 | (err, updatedPost) => {
75 | if (err) {
76 | next({
77 | log: 'Error updating post. Please check middleware syntax.',
78 | });
79 | } else {
80 | // changed to.json
81 | // res.status(200).send(newPost);
82 | res.status(200).json(updatedPost);
83 | }
84 | });
85 | },
86 |
87 | // deletes posts from your feed
88 | deletePost(req, res, next) {
89 | const postTitle = req.params.title;
90 | Post.deleteOne({ listItem: postTitle },
91 | (err) => {
92 | if (err) {
93 | next({
94 | log: 'Error deleting post. Please check middleware syntax.',
95 | });
96 | } else {
97 | res.sendStatus(200);
98 | }
99 | });
100 | },
101 | };
102 |
103 | module.exports = PostController;
104 |
--------------------------------------------------------------------------------
/client/components/BucketlistItemDisplay.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useState, useEffect } from 'react'
3 | import { json } from 'express';
4 | import AddPostForm from './AddPostForm.jsx'
5 | import CompletedBucketlistItem from './CompletedBucketlistItem.jsx'
6 | import UncompletedBucketlistItem from './UncompletedBucketlistItem.jsx'
7 | import DisplayPost from './DisplayPost.jsx'
8 |
9 | function BucketlistItemDisplay(props) {
10 | const [state, setState] = useState(props.item);
11 | setState(...state, state.images = [])
12 | setState(...state, state.handleImagesChange = '')
13 |
14 | function handleCheckedOffClick(listItem) {
15 |
16 | useEffect(() => {
17 | const updatedItem = {
18 | isChecked: true,
19 | mustAddPost: true
20 | }
21 |
22 | fetch(`/api/listItems/${listItem}`,{
23 | method: 'POST',
24 | headers: {
25 | 'Content-Type': 'application/json'
26 | },
27 | body: updatedItem
28 | })
29 | .then(res => res.json())
30 | .then(data => {
31 | setState(...state, state.isChecked = true, state.mustAddPost = true)
32 | })
33 | .catch(error => {
34 | console.log(error)
35 | })
36 | })
37 |
38 |
39 |
40 |
41 |
42 | }
43 |
44 | function handleDateChange(e) {
45 | e.preventDefault()
46 | const newValue = e.target.value;
47 |
48 | setState(...state, state.dateCompleted = newValue)
49 | }
50 |
51 | function handleBodyOfPostChange(e) {
52 | e.preventDefault()
53 | const newValue = e.target.value;
54 |
55 | setState(...state, state.postDescription = newValue)
56 | }
57 |
58 | function handleYoutubeURLChange(e) {
59 | e.preventDefault()
60 | const newValue = e.target.value;
61 |
62 | setState(...state, state.youtubeLink = newValue)
63 | }
64 |
65 | function handleEmbedGoogleMaps(e) {
66 | // NOT SURE YET HOW TO DO THIS ONE!!
67 | e.preventDefault()
68 | const newValue = e.target.value;
69 |
70 | setState(...state, state.location = newValue)
71 | }
72 |
73 | function handleSubmitPostClick() {
74 |
75 | useEffect(() => {
76 | const newPost = {
77 | listItem: state.listItem,
78 | date: state.dateCompleted,
79 | postDescription: state.postDescription,
80 | youtubeLink: state.youtubeLink,
81 | location: state.googleLink,
82 | images: state.images
83 | }
84 |
85 | fetch('/api/post/compelete-bucket-list-item', {
86 | method: 'PUT',
87 | headers: {
88 | 'Content-Type': 'application/json'
89 | },
90 | body: newPost
91 | })
92 | .then(res => res.json())
93 | .then(data => {
94 | console.log(data)
95 | setState(...state, state.mustAddPost = false)
96 | })
97 | .catch(error => {
98 | console.log(error)
99 | })
100 | })
101 | }
102 |
103 | function handleGoogleLinkChange(e) {
104 | e.preventDefault()
105 | const newValue = e.target.value;
106 |
107 | setState(...state, state.googleLink = newValue)
108 | }
109 |
110 | function handleAddImagesChange(e){
111 | e.preventDefault()
112 | const newValue = e.target.value;
113 |
114 | setState(...state, state.handleImagesChange = newValue)
115 | }
116 |
117 | function handleAddImagesClick() {
118 | setState(...state, state.images.push(state.handleImagesChange))
119 | setState(...state, state.handleImagesChange = '');
120 |
121 | }
122 |
123 |
124 |
125 | if (state.isChecked && state.mustAddPost) {
126 |
127 | return (
128 |
146 | )
147 | } else if (state.item.isChecked) {
148 | return (
149 |
155 | )
156 | } else {
157 |
158 | return (
159 |
166 | )
167 | }
168 |
169 | }
170 |
171 | export default BucketlistItemDisplay;
172 |
173 |
174 | // make only one dexcription
175 |
176 | // const newPost = {
177 | // listItem,
178 | // dateCompleted,
179 | // // some sort of access to an embedded google map
180 | // // add a date the listItem was created
181 | // dateCreated,
182 | // location,
183 | // postDescription,
184 | // // maybe rename to originalDescription
185 | // // REMOVE DESCRIPTION
186 | // description,
187 | // youtubeLink,
188 | // hasCompleted,
189 | // mustAddPost
190 | // // Image upload parameter.
191 | // }
--------------------------------------------------------------------------------