├── .eslintrc.js
├── .gitignore
├── .vscode
└── settings.json
├── README.md
├── package-lock.json
├── package.json
├── server
├── controllers
│ └── petLoggerController.js
├── models
│ └── petLoggerModels
├── routers
│ └── petLoggerRouter.js
└── server.js
├── src
├── App.jsx
├── components
│ ├── AddNewComponent.jsx
│ ├── DependentComponent.jsx
│ ├── DogIcon.jsx
│ ├── HelpIcon.jsx
│ ├── LogComponent.jsx
│ ├── NavComponent.jsx
│ ├── NewLogComponent.jsx
│ └── SettingIcon.jsx
├── containers
│ ├── DependentContainer.jsx
│ ├── MainContainer.jsx
│ └── UserProfileContainer.jsx
├── images
│ ├── pet_supplies_FILL0_wght400_GRAD0_opsz24.svg
│ └── pets_FILL0_wght400_GRAD0_opsz24.svg
├── index.html
├── index.js
└── stylesheets
│ └── style.css
└── webpack.config.js
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | browser: true,
4 | es2021: true,
5 | },
6 | extends: 'plugin:react/recommended',
7 | overrides: [
8 | {
9 | env: {
10 | node: true,
11 | },
12 | files: ['.eslintrc.{js,cjs}'],
13 | parserOptions: {
14 | sourceType: 'script',
15 | },
16 | },
17 | ],
18 | parserOptions: {
19 | ecmaVersion: 'latest',
20 | sourceType: 'module',
21 | },
22 | plugins: ['react'],
23 | rules: {
24 | indent: ['warn', 2],
25 | 'no-unused-vars': ['off', { vars: 'local' }],
26 | 'prefer-const': 'warn',
27 | quotes: ['warn', 'single'],
28 | semi: ['warn', 'always'],
29 | 'space-infix-ops': 'warn',
30 | },
31 | };
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | dist/
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cSpell.words": ["Bongi"]
3 | }
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Pet-Logger
2 | Keep track of your pets and their activities!
3 |
4 | ## Scratch Project Team:
5 | - Neul Seo - [neulseo2](https://github.com/neulseo2)
6 | - Reem Abi Ammar - [RGA29](https://github.com/RGA29)
7 | - Michael Underbrink - [MUnderbrink90](https://github.com/MUnderbrink90)
8 | - Bongi Sibanda - [trialnerr](https://github.com/trialnerr)
9 | - Evan Griffith - [EvanCG](https://github.com/EvanCG)
10 |
11 | ## Iteration Project Team:
12 | - Adeeb Bayat - [adeebbayat](https://github.com/adeebbayat)
13 | - Emma Ijiogbe - [emmagawd](https://github.com/emmagawd)
14 | - Marselena Romero - [marsbird](https://github.com/marsbird)
15 | - Howard Sun - [howardCodeGit](https://github.com/howardCodeGit)
16 | - Lillian Tenn - [tenn501](https://github.com/tenn501)
17 |
18 | ## Installation
19 |
20 | Clone repo (`dev` = development, `main` = production)
21 |
22 | ```
23 | npm install
24 | ```
25 |
26 | Run the dev server:
27 | ```
28 | npm run dev
29 | ```
30 | Build `bundle.js`
31 | ```
32 | npm run build
33 | ```
34 |
35 | Run production:
36 | ```
37 | npm start
38 | ```
39 |
40 | ## Resources
41 |
42 | [Original Project Brief](https://docs.google.com/document/d/1FRxqzQAyEkf6vKRIRw1K4uQE90Ns0TCO/edit)
43 |
44 | [Excalidraw](https://excalidraw.com/#room=cfdad5ee56f4643e116a,x7qBxZRVR2t59n9GJfMYBQ) - High level Mongo Shema, and UI frameworks. Note: Excalidraw shared files do not retain history, so be careful!
45 |
46 | [Scrum Board](https://team-omydjgcen49r.atlassian.net/jira/software/projects/GGS/boards/1).
47 |
48 | [#gobin-shark-scratch-project slack channel](https://codesmithecri46.slack.com/archives/C06N9RH4L87)
49 |
50 | [Iteration Project Brief](https://docs.google.com/document/d/18PJVy5rqm_WkpULniAe3l4CnA7rD-iY7/edit)
51 |
52 | ### Routes
53 |
54 | Almost all requests defined in `server/routers/petLoggerRouter.js` and `server/controllers/petLogger/Controller.js`, so check there for source of truth.
55 |
56 | **POST request to add new dog**
57 | ```
58 | Method: POST
59 | Endpoint: localhost:3000/api/dog
60 | Body: { name, breed, age, gender }
61 | Controller Method: addDog
62 | Return: newDog object
63 | ```
64 |
65 | **GET dogs of user**
66 | ```
67 | METHOD: GET
68 | Endpoint: localhost:3000/api/dog/:user
69 | Controller method: getDogs
70 | Response: array of matching dog objects
71 | ```
72 |
73 | **GET for all posts of dog**
74 | ```
75 | Method: GET
76 | Endpoint: localhost:3000/api/post (query dogId)
77 | Controller mtehod: getPost
78 | Response: array of post objects [{postType, details, date}]
79 | ```
80 |
81 | **POST for new activity to dog**
82 | ```
83 | Method: POST
84 | Endpoint: localhost:3000/api/post
85 | Body: { dogID, postType, details }
86 | controller Method: addPost
87 | Response: New Post object
88 | ```
89 |
90 | ### Database
91 |
92 | MongoDB backend is associated with [trialnerr](https://github.com/trialnerr)'s account. IP Address allowlists will need to be explicitly indicated in order to read/write.
93 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pet-logger",
3 | "version": "1.0.0",
4 | "description": "Javascript-project",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "node server/server.js",
8 | "build": "webpack --mode production",
9 | "dev": "nodemon server/server.js & NODE_ENV=development webpack serve --open --hot",
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "keywords": [],
13 | "author": "",
14 | "license": "ISC",
15 | "dependencies": {
16 | "dotenv": "^16.4.5",
17 | "mongodb": "^6.4.0",
18 | "mongoose": "^8.2.1",
19 | "nodemon": "^3.1.0",
20 | "pg": "^8.11.3",
21 | "react": "^18.2.0",
22 | "react-router": "^4.3.1",
23 | "react-dom": "^18.2.0",
24 | "react-router-dom": "^6.22.3"
25 | },
26 | "devDependencies": {
27 | "@babel/core": "^7.24.0",
28 | "@babel/preset-env": "^7.24.0",
29 | "@babel/preset-react": "^7.23.3",
30 | "babel-loader": "^9.1.3",
31 | "css-loader": "^6.10.0",
32 | "eslint": "^8.57.0",
33 | "eslint-plugin-react": "^7.34.0",
34 | "file-loader": "^6.2.0",
35 | "html-webpack-plugin": "^5.6.0",
36 | "sass": "^1.71.1",
37 | "sass-loader": "^14.1.1",
38 | "style-loader": "^3.3.4",
39 | "svg-inline-loader": "^0.8.2",
40 | "webpack": "^5.90.3",
41 | "webpack-cli": "^5.1.4",
42 | "webpack-dev-server": "^5.0.2"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/server/controllers/petLoggerController.js:
--------------------------------------------------------------------------------
1 | // DOG {
2 | // DogID: integer,
3 | // Name: string,
4 | // Age: number,
5 | // Breed: string
6 | // gender: string,
7 | // Users: [userID: integer]
8 | // Posts: [{postType: string, details: string, date:date}]
9 | // }
10 |
11 | // GET REQUEST TO LOAD ALL DEPENDENTS. Info needed: name and image and id. Type for response : ARRAY of dog objects
12 | // Method: GET
13 | // Endpoint: /dog
14 | // ControllerMethod:
15 | // Response format:
16 |
17 | // Method: POST
18 | // Endpoint: localhost:3000/dog
19 | // Body: { name, breed, age, gender }
20 | // Controller Method: addDog
21 | const model = require('../models/petLoggerModels');
22 | const petLoggerController = {};
23 |
24 | // GET: middleware for retreiving a dog data
25 | petLoggerController.getDogs = async (req, res, next) => {
26 | try {
27 | //retrieve the userId from req.params
28 | console.log('req params', req.params);
29 | const userId = req.params.user;
30 | //get all the dogs from the database
31 | const dogs = await model.Dog.find({});
32 | console.log({ dogs });
33 | // for each dog returned, check if the usersarray contained the userId
34 | const matchingDogs = dogs.filter((dog) => dog.users.includes(userId));
35 | res.locals.matchingDogs = matchingDogs;
36 | return next();
37 | } catch (err) {
38 | // handle errors
39 | return next({
40 | log: `Error in getDog middleware ${err}`,
41 | status: 500,
42 | message: `Error in getDog middleware`,
43 | });
44 | }
45 | };
46 |
47 | // petLoggerController.getDogs2 = async (req, res, next) => {
48 | // try {
49 | // //retrieve the userId from req.params
50 | // const userId = req.params.user;
51 | // //get all the dogs from the database
52 | // const dogs = await model.Dog.find({ $in: ['$userId', '$users'] });
53 | // // for each dog returned, check if the usersarray contained the userId
54 | // res.locals.matchingDogs = dogs;
55 | // return next();
56 | // } catch (err) {
57 | // // handle errors
58 | // return next({
59 | // log: `Error in getDog middleware ${err}`,
60 | // status: 500,
61 | // message: `Error in getDog middleware`,
62 | // });
63 | // }
64 | // };
65 |
66 | // POST: middleware for adding a new dog
67 | petLoggerController.addDog = async (req, res, next) => {
68 | try {
69 | // declare the constants we're going to use
70 | const { name, breed, age, gender } = req.body;
71 | // async connect to the mongo DB, and create a new dog
72 | const newDog = await model.Dog.create({ name, breed, age, gender });
73 | // save the dog object in res.locals as newDog
74 | res.locals.newDog = newDog;
75 | console.log("newDog", res.locals.newDog)
76 | return next();
77 | } catch (err) {
78 | // handle errors
79 | return next({
80 | log: `Error in addDog middleware ${err}`,
81 | status: 500,
82 | message: `Error in addDog middleware`,
83 | });
84 | }
85 | };
86 |
87 | // POST: middleware for adding a new user
88 | petLoggerController.addUser = async (req, res, next) => {
89 | try {
90 | const { name, username, password } = req.body;
91 | const newUser = await model.User.create({ name, username, password });
92 | res.locals.newUser = newUser;
93 | return next();
94 | } catch (err) {
95 | // handle errors
96 | return next({
97 | log: `Error in addUser middleware ${err}`,
98 | status: 500,
99 | message: `Error in addUser middleware`,
100 | });
101 | }
102 | };
103 |
104 | // POST: for adding a new post for a dependent(dog)
105 | petLoggerController.addPost = async (req, res, next) => {
106 | try {
107 | const { dogId, postType, details } = req.body;
108 |
109 | // update the dog object to have a new post in its post array
110 | // update we'll make is pushing a new post into the posts array on the dog
111 | // we'll return just the new post
112 |
113 | const filter = { _id: dogId };
114 | const update = { $push: { posts: { postType, details } } };
115 |
116 | const dog = await model.Dog.findOneAndUpdate(filter, update, { new: true });
117 | // console.log(dog.posts);
118 | res.locals.dog = dog.posts[dog.posts.length - 1];
119 | return next();
120 | } catch (err) {
121 | // handle errors
122 | return next({
123 | log: `Error in addPost middleware ${err}`,
124 | status: 500,
125 | message: `Error in addPost middleware ${err}`,
126 | });
127 | }
128 | };
129 |
130 | // GET: for getting all dogs posts when given dog Id in req.query
131 | petLoggerController.getPost = async (req, res, next) => {
132 | try {
133 | const { dogId } = req.query;
134 | const foundDog = await model.Dog.find({ _id: dogId });
135 | console.log(foundDog[0].posts);
136 | res.locals.posts = foundDog[0].posts;
137 |
138 | return next();
139 | } catch (error) {
140 | return next({
141 | log: `Error in getPost middleware ${err}`,
142 | status: 500,
143 | message: `Error in getPost middleware ${err}`,
144 | });
145 | }
146 | };
147 |
148 | module.exports = petLoggerController;
149 |
--------------------------------------------------------------------------------
/server/models/petLoggerModels:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 | // const { MongoClient, ServerApiVersion } = require('mongodb');
3 | const { Schema } = mongoose;
4 |
5 | const uri =
6 | 'mongodb+srv://bongisiba:9amflRSy13ObViXE@petloggercluster.afs6n5g.mongodb.net/?retryWrites=true&w=majority&appName=PetLoggerCluster';
7 |
8 | mongoose
9 | .connect(uri, {
10 | // options for the connect method to parse the URI
11 | // sets the name of the DB that our collections are part of
12 | dbName: 'petLogger',
13 | })
14 | .then(() => console.log('Connected to Mongo DB.'))
15 | .catch((err) => console.log(err));
16 |
17 | //user Schema
18 | const userSchema = new Schema({
19 | name: { type: String, required: true, unique: true },
20 | userName: { type: String, required: true },
21 | password: { type: String, required: true },
22 | });
23 |
24 | const User = mongoose.model('user', userSchema);
25 |
26 | //dogSchema
27 | const dogSchema = new Schema({
28 | name: { type: String, required: true },
29 | age: { type: Number },
30 | breed: { type: String },
31 | gender: { type: String },
32 | // users: [
33 | // {
34 | // userId: {
35 | // type: Schema.Types.ObjectId,
36 | // ref: 'user',
37 | // },
38 | // userId: {
39 | // type: Schema.Types.ObjectId,
40 | // default: '65ecbe30d6da6de8222431e2'
41 | // }
42 | // },
43 | // ],
44 | users: {
45 | type: [Schema.Types.ObjectId],
46 | default: ['65ecbe30d6da6de8222431e2'],
47 | },
48 | posts: [
49 | {
50 | postType: String,
51 | details: String,
52 | date: { type: Date, default: Date.now },
53 | },
54 | ],
55 | });
56 |
57 | const Dog = mongoose.model('dog', dogSchema);
58 |
59 | module.exports = {
60 | User,
61 | Dog,
62 | };
63 |
--------------------------------------------------------------------------------
/server/routers/petLoggerRouter.js:
--------------------------------------------------------------------------------
1 | //Importing express and creating our router
2 | const express = require('express');
3 | const router = express.Router();
4 |
5 | // import our relevante controllers
6 | const petLoggerController = require('../controllers/petLoggerController');
7 | /* WHAT IS THIS FILE DOING?
8 | use the controllers based on what kind of a request is coming in
9 | define the endpoint and method
10 | run middleware
11 | send a response back
12 | */
13 |
14 | // Create a new dog
15 | // Method: POST
16 | // Endpoint: localhost:3000/api/dog
17 | // Body: { name, breed, age, gender }
18 | // Controller Method: addDog
19 | // Return: newDog object
20 | router.post('/dog', petLoggerController.addDog, (req, res) => {
21 | res.status(200).json(res.locals.newDog);
22 | });
23 |
24 | // get a user's dogs
25 | // METHOD: GET
26 | // Endpoint: localhost:3000/api/dog/:user
27 | // Controller method: getDogs
28 | // Response: array of matching dog objects
29 |
30 | router.get('/dog/:user', petLoggerController.getDogs, (req, res) => {
31 | res.status(200).json(res.locals.matchingDogs);
32 | });
33 |
34 | // Get a dog's posts
35 | // Method: GET
36 | // Endpoint: localhost:3000/api/post (query: dogId)
37 | // Controller mtehod: getPost
38 | // Response: array of post objects [{postType, details, date}]
39 | router.get('/post', petLoggerController.getPost, (req, res) => {
40 | res.status(200).json(res.locals.posts);
41 | });
42 |
43 | //add new activity
44 | //Method: POST
45 | // Endpoint: localhost:3000/api/post
46 | // Body: { dogID, postType, details }
47 | // controller Method: addPost
48 | // Response: updated dog object
49 | router.post('/post', petLoggerController.addPost, (req, res) => {
50 | res.status(200).json(res.locals.dog);
51 | });
52 |
53 | // POST to USER => create a new user
54 | // Method: POST
55 | // Endpoint: localhost:3000/api/user
56 | // Body: { username, name, password }
57 | // Controller Method: addUser
58 | // Return: newUser object
59 | router.post('/user', petLoggerController.addUser, (req, res) => {
60 | res.status(200).json(res.locals.addUser);
61 | });
62 |
63 | // export this file
64 | module.exports = router;
65 |
--------------------------------------------------------------------------------
/server/server.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const express = require('express');
3 | const petLoggerRouter = require('./routers/petLoggerRouter');
4 |
5 | const app = express();
6 | const PORT = 3000;
7 |
8 | if (process.env.NODE_ENV === 'development') {
9 | app.use(express.static(path.resolve(__dirname, '../src')));
10 | } else {
11 | app.use(express.static(path.resolve(__dirname, '../dist')));
12 | }
13 |
14 | // parsing requests to json
15 | app.use(express.json());
16 | // define the route handlers
17 | app.use('/api', petLoggerRouter);
18 |
19 | // Unkown route handler here
20 | app.use('*', (req, res) => {
21 | console.log('This is 404');
22 | res.sendStatus(404);
23 | });
24 |
25 | // Global error handler
26 | app.use((err, req, res, next) => {
27 | const defaultErr = {
28 | log: 'Error from middleware',
29 | status: 500,
30 | message: { err: 'ERROR!!!' },
31 | };
32 |
33 | const errorObj = Object.assign({}, defaultErr, err);
34 |
35 | return res.status(errorObj.status).json(errorObj.message);
36 | });
37 |
38 | app.listen(PORT, () => {
39 | console.log(`server listening on port ${PORT}: http://localhost:${PORT}/`);
40 | });
41 |
42 | module.exports = app;
43 |
--------------------------------------------------------------------------------
/src/App.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Routes, Route } from 'react-router-dom';
3 |
4 | import MainContainer from "./containers/MainContainer";
5 | import UserProfileContainer from "./containers/UserProfileContainer";
6 | import DependentContainer from "./containers/DependentContainer";
7 | import AddNewComponent from "./components/AddNewComponent";
8 | import NavComponent from "./components/NavComponent";
9 |
10 |
11 |
12 | const App = () => {
13 | return (
14 |
15 | {/*
Michael was up in here!
16 |
This is Reem
17 |
Hello Guys Bongi
*/}
18 |
19 |
20 |
21 |
22 |
23 | } />
24 | }/>
25 | }/>
26 |
27 |
28 |
29 |
30 | {/* */}
31 |
32 |
33 |
34 | );
35 | };
36 |
37 | export default App;
--------------------------------------------------------------------------------
/src/components/AddNewComponent.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 | import { useState, useEffect } from 'react';
4 | //import { useNavigate } from "react-router-dom";
5 |
6 | const breedArray = [
7 | 'Husky',
8 | 'Golden Retreiver',
9 | 'Dalmatian',
10 | 'German Shepard',
11 | 'Lab',
12 | 'Beagle',
13 | 'Poodle',
14 | ];
15 |
16 | const useInput = (init) => {
17 | const [value, setValue] = useState(init);
18 | const onChange = (e) => {
19 | setValue(e.target.value);
20 | };
21 | return [value, onChange];
22 | };
23 |
24 | const AddNewComponent = () => {
25 | const breedlist = [
26 | { label: "German Shepard", value: "German Shepard" },
27 | { label: "Lab", value: "Lab" },
28 | { label: "Husky", value: "Husky" },
29 | { label: "Dalmatian", value: "Dalmatian" },
30 | ];
31 |
32 | const genderList = [
33 | { label: "male", value: "male" },
34 | { label: "female", value: "female" },
35 | ];
36 |
37 | const [name, nameOnChange] = useInput("");
38 | const [age, ageOnChange] = useInput("");
39 | const [breed, breedOnChange] = useInput("");
40 | const [gender, genderOnChange] = useInput("");
41 |
42 | const saveCharacter = () => {
43 | // check if name is empty
44 | const body = {
45 | name,
46 | age,
47 | breed,
48 | gender,
49 | };
50 | console.log('req.body', body);
51 |
52 | fetch("/api/dog", {
53 | method: "POST",
54 | headers: {
55 | "Content-Type": "Application/JSON",
56 | },
57 | body: JSON.stringify(body),
58 | })
59 | .then((resp) => resp.json())
60 |
61 | .catch((err) =>
62 | console.log(" add dependent fetch /api/character: ERROR: ", err)
63 | );
64 | };
65 |
66 |
67 | return (
68 |
131 | );
132 | };
133 |
134 | export default AddNewComponent;
135 |
--------------------------------------------------------------------------------
/src/components/DependentComponent.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 |
4 | // import DependentContainer from './DependentContainer';
5 |
6 | // to add link to the dependent page
7 |
8 | const DependentComponent = ({ traits }) => {
9 | const dogImages = {
10 | 'German Shepard':
11 | 'https://images.pexels.com/photos/236622/pexels-photo-236622.jpeg',
12 | Lab: 'https://images.pexels.com/photos/4000307/pexels-photo-4000307.jpeg',
13 | Husky: 'https://images.pexels.com/photos/245035/pexels-photo-245035.jpeg',
14 | Dalmatian:
15 | 'https://images.pexels.com/photos/13764529/pexels-photo-13764529.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2',
16 | };
17 |
18 | const { _id, name, age, breed, gender } = traits;
19 | console.log({ breed });
20 |
21 | return (
22 |
23 |
24 | {/*

*/}
25 |

26 |
27 |
28 |
29 | {name}
30 |
31 |
32 | - Age: {age}
33 | - Breed: {breed}
34 | - Gender: {gender}
35 |
36 |
37 |
38 | );
39 | };
40 |
41 | export default DependentComponent;
42 |
--------------------------------------------------------------------------------
/src/components/DogIcon.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 |
4 |
5 | const DogIcon = () => {
6 |
7 |
8 | return (
9 |
10 |
11 | );
12 | }
13 |
14 | export default DogIcon;
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/components/HelpIcon.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 |
4 |
5 | const HelpIcon = () => {
6 |
7 |
8 | return (
9 |
12 |
13 | );
14 | }
15 |
16 | export default HelpIcon;
--------------------------------------------------------------------------------
/src/components/LogComponent.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const LogComponent = ({ logs }) => {
4 | const { postType, details, date } = logs;
5 |
6 | let formatDate = date.substring(0,10)
7 | formatDate = formatDate.split('-');
8 | formatDate = formatDate.reverse().join('/')
9 |
10 | let formatTime = date.substring(11, 16)
11 |
12 | return (
13 |
14 |

15 | {/*
Oil Rig Placeholder
*/}
16 |
17 | {postType}
18 | {details}
19 | {`${formatDate} at ${formatTime}`}
20 |
21 |
22 | );
23 | };
24 |
25 | export default LogComponent;
26 |
--------------------------------------------------------------------------------
/src/components/NavComponent.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import SettingIcon from './SettingIcon';
4 | import HelpIcon from './HelpIcon';
5 | import DogIcon from './DogIcon';
6 |
7 |
8 |
9 | const NavComponent = () => {
10 |
11 |
12 | return (
13 |
14 |
15 |
PetLogger
16 |
17 |
25 |
26 | )
27 | }
28 |
29 | export default NavComponent;
--------------------------------------------------------------------------------
/src/components/NewLogComponent.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useState, useEffect } from "react";
3 | import { Link } from "react-router-dom";
4 |
5 | const useInput = (init) => {
6 | const [value, setValue] = useState(init);
7 | const onChange = (e) => {
8 | setValue(e.target.value);
9 | };
10 | return [value, onChange];
11 | };
12 |
13 | const NewLogComponent = (props) => {
14 | const [postType, postTypeOnChange] = useInput("");
15 | const [details, detailsOnChange] = useInput("");
16 |
17 | const saveLog = (id) => {
18 | // NEED TO DO FEILD INPUT VALIDATION
19 | const body = {
20 | dogId: id,
21 | postType,
22 | details,
23 | };
24 | fetch("/api/post", {
25 | method: "POST",
26 | headers: {
27 | "Content-Type": "Application/JSON",
28 | },
29 | body: JSON.stringify(body),
30 | })
31 | .then((resp) => resp.json())
32 | .then((data) => {
33 | console.log("request body", data);
34 | window.location.reload();
35 | })
36 | .catch((err) => console.log(" add log fetch: ERROR: ", err));
37 | };
38 |
39 | return (
40 |
41 |
Log new activity
42 |
43 |
73 |
74 | );
75 | };
76 |
77 | export default NewLogComponent;
78 |
--------------------------------------------------------------------------------
/src/components/SettingIcon.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 |
4 |
5 | const SettingIcon = () => {
6 |
7 |
8 | return (
9 |
12 | );
13 | }
14 |
15 | export default SettingIcon;
--------------------------------------------------------------------------------
/src/containers/DependentContainer.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import { withRouter } from "react-router-dom";
3 | import NewLogComponent from "../components/NewLogComponent";
4 | import LogComponent from "../components/LogComponent";
5 |
6 | import DependentComponent from "../components/DependentComponent";
7 | import { useParams } from "react-router-dom";
8 |
9 | const logArray = [{activity:'nap', time:'12:50pm', note: 'Did not want to take a nap.'}, {activity:'medicine', time:'1:50pm', note: 'Gave red pills' }];
10 |
11 | const DependentContainer = (props) => {
12 | const { id } = useParams();
13 | console.log(id);
14 |
15 | // Method: GET
16 | // Endpoint: localhost:3000/api/post?dogId=48374837483743 (query dogId)
17 | // Controller mtehod: getPost
18 | // Response: array of post objects [{postType, details, date}]
19 |
20 | const [log, setLog] = useState([]);
21 | // const [reset, setreset] = useState(false)
22 |
23 | useEffect (() => {
24 | fetch (`/api/post?dogId=${id}`)
25 | .then(resp => resp.json())
26 | .then (data => setLog(data))
27 | .catch((err)=> console.log("get logs request error", err));
28 | }, []);
29 |
30 |
31 | // iterate using a for loop over the data array of objects, pass in the info from each element to a dependent component.
32 |
33 | // const logActivities = log.map((elem, i)=>{
34 | // return (
35 | // );
39 | // });
40 |
41 | let logActivities = [];
42 | for (let i = log.length-1; i>=0; i--){
43 | logActivities.push(
44 |
48 | )
49 | }
50 |
51 |
52 | return (
53 |
54 | {/* */}
57 |
60 | {logActivities}
61 |
62 | );
63 | };
64 |
65 | export default DependentContainer;
66 |
--------------------------------------------------------------------------------
/src/containers/MainContainer.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import DependentContainer from './DependentContainer';
4 | import NavComponent from '../components/NavComponent';
5 |
6 |
7 | const MainContainer = () => {
8 |
9 |
10 | return (
11 |
12 |
13 |
14 | )
15 | }
16 |
17 | export default MainContainer;
--------------------------------------------------------------------------------
/src/containers/UserProfileContainer.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import {withRouter} from 'react-router-dom';
3 | import { Link } from 'react-router-dom';
4 |
5 | import DependentComponent from "../components/DependentComponent";
6 |
7 |
8 | // const dogArray = [{name: "Oil Rig", breed:"German Shepard", age: 5, gender: 'female'}, {name: "Shadow", breed:"German Shepard", age: 7, gender: 'male'}, {name: "Penelope", breed:"Grey Hound", age: 2, gender: 'female'}, {name: "Antonio", breed:"English Bulldog", age: 10, gender: 'male'}]
9 |
10 | const DependentContainer = () => {
11 |
12 | const [result, setResult] = useState([]);
13 |
14 | useEffect (() => {
15 | fetch ('/api/dog/65ecbe30d6da6de8222431e2')
16 | .then(resp => resp.json())
17 | .then((data)=> setResult(data)) // data is going to be an array of objects
18 | .catch((err)=> console.log("get dependents request error", err));
19 |
20 | }, []);
21 |
22 |
23 | // console.log("dogarray", dogArray)
24 | // console.log("dependents", dependents)
25 |
26 | const dependents = result.map((elem, i)=>{
27 | return (
28 | );
32 | });
33 |
34 | return (
35 |
36 |
Dependents you are tracking
37 |
38 |
{dependents}
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | );
47 | };
48 |
49 | export default DependentContainer;
50 |
--------------------------------------------------------------------------------
/src/images/pet_supplies_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/images/pets_FILL0_wght400_GRAD0_opsz24.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Pet Logger
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 | import { BrowserRouter, HashRouter } from 'react-router-dom';
5 |
6 | import styles from './stylesheets/style.css';
7 |
8 | ReactDOM.render(
9 |
10 |
11 | ,
12 | document.getElementById('root')
13 | );
--------------------------------------------------------------------------------
/src/stylesheets/style.css:
--------------------------------------------------------------------------------
1 |
2 | @import url('https://fonts.googleapis.com/css2?family=Madimi+One&display=swap');
3 |
4 | * {
5 | margin: 0;
6 | padding: 0;
7 | box-sizing: border-box;
8 | font-family: Arial, Helvetica, sans-serif;
9 | }
10 |
11 | body {
12 | background: whitesmoke;
13 | }
14 |
15 | .navheader {
16 | width: 100%;
17 | padding: 10px 20px;
18 | background: rgba(0, 145, 255, 0.69);
19 | display: flex;
20 | align-items: center;
21 | justify-content: space-between;
22 | }
23 |
24 | .logo {
25 | font-size: 1.5rem;
26 | color: whitesmoke;
27 | text-decoration: none;
28 | font-family: "Madimi One", sans-serif;
29 | font-weight: 400;
30 | font-style: normal;
31 |
32 | }
33 | .logo svg{
34 | color: whitesmoke;
35 |
36 | }
37 |
38 |
39 | .navbar{
40 | display: flex;
41 | align-items: center;
42 | justify-content: space-between;
43 | }
44 |
45 | .profileinfocontainer {
46 | background: rgba(0, 145, 255, 0.69);
47 | padding: 5px 10px;
48 | color: whitesmoke;
49 | border: solid rgba(0, 145, 255, 0.69);;
50 | border-radius: 5px;
51 | display: flex;
52 | align-items: center;
53 | justify-content: center;
54 | }
55 |
56 | .profileinfocontainer img{
57 | height: 30px;
58 | width: 30px;
59 | border-radius: 50%;
60 | margin-right: 0px;
61 |
62 | }
63 |
64 | .profileinfocontainer span {
65 | margin-left: 10px;
66 |
67 | }
68 |
69 |
70 | .navbar a {
71 | font-size: 1rem;
72 | color: white;
73 | font-weight: 500;
74 | text-decoration: none;
75 | margin-left: 20px;
76 |
77 | }
78 |
79 | .navbar svg{
80 | color: whitesmoke;
81 |
82 | }
83 |
84 |
85 | /*User Container styles*/
86 | .usermaincontainer {
87 | /* border: solid black; */
88 | /* background: whitesmoke; */
89 |
90 | }
91 | .usermaincontainer h2{
92 | margin: 10px 20px;
93 | color: rgba(0, 145, 255, .69);
94 | font-weight: 300;
95 |
96 | }
97 | .buttoncontainer{
98 | width: 100%;
99 | /* text-align: right; */
100 | margin-top: 20px;
101 | }
102 |
103 | .buttoncontainer button{
104 | float: right;
105 | padding: 10px;
106 | margin-right: 20px;
107 | background: rgba(0, 145, 255, 1);
108 | color: white;
109 | border: none;
110 | border-radius: 5px;
111 |
112 |
113 | }
114 |
115 | .alldependents{
116 | border: solid thin grey;
117 | background-color: white;
118 | display: flex;
119 | flex-wrap: wrap;
120 | /* flex-direction: column; */
121 | align-items: center;
122 | justify-content: flex-start;
123 |
124 | }
125 |
126 | .dependentcomponent{
127 | border: solid rgba(0, 145, 255, 0.69);
128 | border-radius: 10px;
129 | background: rgba(0, 145, 255, 0.1);
130 | width: 325px;
131 | height: 150px;
132 | padding: 20px;
133 | margin: 20px;
134 | display: flex;
135 | align-items: center;
136 | /* justify-content: space-around; */
137 |
138 | }
139 |
140 | .dependentimgcontainer img {
141 | height: 100px;
142 | width: 100px;
143 | border-radius: 50%;
144 |
145 | }
146 |
147 | .dependentname h3{
148 | text-decoration: none;
149 | }
150 |
151 | .dependentinfocontainer {
152 | padding: 10px;
153 | margin-left: 20px;
154 | }
155 |
156 | .dependentinfocontainer li{
157 | text-decoration: none;
158 | list-style: none;
159 | }
160 |
161 |
162 | /*Add new form styling*/
163 | .addnewcomponent{
164 | display: flex;
165 | justify-content: center;
166 | align-items: center;
167 | background-color: whitesmoke;
168 | padding: 50px;
169 | }
170 |
171 | .formwrapper{
172 | width: 420px;
173 | background: rgba(0, 145, 255, 0.1);
174 | border: solid rgba(0, 145, 255, 0.69);
175 | border-radius: 5px;
176 | padding: 20px;
177 | }
178 |
179 | .formwrapper h3{
180 | margin-bottom: 10px;
181 | font-weight: bold;
182 | text-align: center;
183 | color: rgba(0, 145, 255, 0.8);
184 | }
185 |
186 | .formwrapper input {
187 | width: 100%;
188 | padding: 5px;
189 | margin-top: 5px;
190 | margin-bottom: 10px;
191 |
192 | }
193 |
194 | .formwrapper select {
195 | width: 100%;
196 | padding: 5px;
197 | margin-top: 5px;
198 | margin-bottom: 10px;
199 |
200 | }
201 |
202 | .formwrapper label {
203 | margin-top: 20px;
204 | }
205 |
206 |
207 | .cancel{
208 | float: right;
209 | padding: 10px;
210 | background: none;
211 | color: rgba(0, 145, 255, 1);
212 | border: solid rgba(0, 145, 255, 1);
213 | border-radius: 5px;
214 | min-width: 100px;
215 | margin-right: 5px;
216 | }
217 |
218 | .submitnew{
219 | float: right;
220 | padding: 10px;
221 | background: rgba(0, 145, 255, 1);
222 | color: white;
223 | border: solid rgba(0, 145, 255, 1);
224 | border-radius: 5px;
225 | min-width: 100px;
226 | margin-left: 5px;
227 | }
228 |
229 | /*activity log page*/
230 |
231 | .dependentpagecontainer{
232 | background: whitesmoke;
233 | display: flex;
234 | flex-direction: column;
235 | align-items: baseline;
236 |
237 | }
238 |
239 | .newlogcontainer {
240 | margin-top: 20px;
241 | border: solid rgba(0, 145, 255, 0.69);
242 | border-radius: 10px;
243 | background: rgba(0, 145, 255, 0.1);
244 | width: 700px;
245 | height: 150px;
246 | padding: 20px;
247 | margin: 20px;
248 |
249 | }
250 |
251 | .newlogcontainer h4 {
252 | margin-bottom: 10px;
253 | font-weight: bold;
254 | text-align: left;
255 | color: rgba(0, 145, 255, 0.8);
256 | }
257 |
258 | .logforminputs select{
259 | margin-right: 20px;
260 | padding: 4px;
261 | border-radius: 5px;
262 | width: 20%;
263 | border: solid thin rgba(0, 145, 255, 0.8);
264 | }
265 |
266 | .logforminputs input{
267 | /* margin-right: 20px; */
268 | width: 75%;
269 | padding: 5px;
270 | border-radius: 5px;
271 | border: solid thin rgba(0, 145, 255, 0.8);
272 | }
273 |
274 | .newlogcontainer button {
275 | float: right;
276 | padding: 5px;
277 | background: rgba(0, 145, 255, 1);
278 | color: white;
279 | border: solid rgba(0, 145, 255, 1);
280 | border-radius: 5px;
281 | min-width: 100px;
282 | margin-right: 10px;
283 | margin-top: 10px;
284 | }
285 |
286 | /* individual activity logs style*/
287 |
288 | .logcomponent {
289 | margin-top: 20px;
290 | border: solid rgba(0, 145, 255, 0.1);
291 | border-radius: 10px;
292 | background: rgba(0, 145, 255, 0.69);
293 | color: whitesmoke;
294 | width: 700px;
295 | height: 100px;
296 | padding: 20px;
297 | margin: 20px;
298 | display: flex;
299 | align-items: center;
300 | /* justify-content: space-between; */
301 | }
302 |
303 | .notesIcon {
304 | max-width: 50px;
305 | max-height: 50px;
306 | }
307 |
308 | .loginfo {
309 | display: flex;
310 | justify-content: space-around;
311 | align-items: center;
312 | width: 90%;
313 |
314 |
315 | }
316 |
317 | .activity {
318 | border: solid thin whitesmoke;
319 | border-radius: 10px;
320 | margin: 5px;
321 | padding: 10px;
322 | width: 100px;
323 | text-align: center;
324 | background: rgba(0, 145, 255, 0.69);
325 |
326 |
327 | }
328 |
329 | .details {
330 | border: solid thin whitesmoke;
331 | border-radius: 10px;
332 | margin: 5px;
333 | padding: 10px;
334 | width: 400px;
335 |
336 | }
337 |
338 | .time {
339 | width: 225px;
340 | text-align: center;
341 | border: solid thin whitesmoke;
342 | border-radius: 10px;
343 | padding: 10px 5px ;
344 | background: rgba(0, 145, 255, 0.69);
345 | margin: 5px;
346 |
347 | }
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const path = require('path');
3 | const HTMLWebpackPlugin = require('html-webpack-plugin');
4 |
5 | module.exports = {
6 | entry: './src/index.js',
7 | output: {
8 | path: path.resolve(__dirname, 'dist'),
9 | filename: 'bundle.js',
10 | },
11 | devServer: {
12 | host: 'localhost',
13 | port: 8080,
14 | hot: true,
15 | static: {
16 | directory: path.resolve(__dirname, 'dist')
17 | },
18 | proxy: [{
19 | context: ['/api/**'],
20 | target: 'http://localhost:3000/',
21 | },
22 | ],
23 | },
24 | plugins: [
25 | new HTMLWebpackPlugin({
26 | template: './src/index.html'
27 | })
28 | ],
29 | module: {
30 | rules: [
31 | {
32 | test: /\.jsx?/,
33 | exclude: /node_modules/,
34 | use: {
35 | loader: 'babel-loader',
36 | options: {
37 | presets: ['@babel/env', '@babel/react']
38 | }
39 | }
40 | },
41 | {
42 | test: /\.s?css$/,
43 | use: [ 'style-loader', 'css-loader', 'sass-loader' ],
44 | },
45 |
46 | ]
47 | },
48 | resolve: {
49 | // Enable importing JS / JSX files without specifying their extension
50 | extensions: ['.js', '.jsx'],
51 | },
52 |
53 | };
--------------------------------------------------------------------------------