This commit is contained in:
QkoSad
2023-08-08 16:02:54 +03:00
commit 0a7a469d56
315 changed files with 426907 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
PORT=3001
MONGODB_URI=mongodb+srv://admin:admin@cluster1.ciuxwxd.mongodb.net/personApp?retryWrites=true&w=majority
@@ -0,0 +1,13 @@
{
"files": {
"main.css": "/static/css/main.305410ed.css",
"main.js": "/static/js/main.dde63dc0.js",
"index.html": "/index.html",
"main.305410ed.css.map": "/static/css/main.305410ed.css.map",
"main.dde63dc0.js.map": "/static/js/main.dde63dc0.js.map"
},
"entrypoints": [
"static/css/main.305410ed.css",
"static/js/main.dde63dc0.js"
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

+1
View File
@@ -0,0 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><script defer="defer" src="/static/js/main.dde63dc0.js"></script><link href="/static/css/main.305410ed.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

+25
View File
@@ -0,0 +1,25 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
+3
View File
@@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
@@ -0,0 +1,2 @@
.error{color:red}.error,.normal{background:#d3d3d3;border-radius:5px;border-style:solid;font-size:20px;margin-bottom:10px;padding:10px}.normal{color:green}
/*# sourceMappingURL=main.305410ed.css.map*/
@@ -0,0 +1 @@
{"version":3,"file":"static/css/main.305410ed.css","mappings":"AAAA,OACE,SAOF,CACA,eAPE,kBAAqB,CAGrB,iBAAkB,CADlB,kBAAmB,CADnB,cAAe,CAIf,kBAAmB,CADnB,YAWF,CARA,QACE,WAOF","sources":["index.css"],"sourcesContent":[".error {\n color: red;\n background: lightgrey;\n font-size: 20px;\n border-style: solid;\n border-radius: 5px;\n padding: 10px;\n margin-bottom: 10px;\n}\n.normal {\n color: green;\n background: lightgrey;\n font-size: 20px;\n border-style: solid;\n border-radius: 5px;\n padding: 10px;\n margin-bottom: 10px;\n}\n"],"names":[],"sourceRoot":""}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,39 @@
/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,39 @@
/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,39 @@
/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,39 @@
/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,39 @@
/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,39 @@
/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,39 @@
/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,39 @@
/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,39 @@
/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
File diff suppressed because one or more lines are too long
+36
View File
@@ -0,0 +1,36 @@
const mongoose = require("mongoose");
mongoose.set("strictQuery", false);
const url = process.env.MONGODB_URI;
console.log("connecting to MongoDB");
mongoose
.connect(url)
.then((res) => {
console.log("connected to MongoDB");
})
.catch((err) => console.log("error connecting to MongoDB", err.message));
const personSchema = new mongoose.Schema({
name: { type: String, minLength: 3 },
number: {
type: String,
validate: {
validator: function (v) {
return /\d{2,3}-\d{5,25}/.test(v);
},
message: (props) => `${props.value} is not a valid phone number!`,
},
required: [true, "User phone number required"],
},
});
personSchema.set("toJSON", {
transform: (document, returnedObject) => {
returnedObject.id = returnedObject._id.toString();
delete returnedObject._id;
delete returnedObject.__v;
},
});
module.exports = mongoose.model("Person", personSchema);
File diff suppressed because it is too large Load Diff
+22
View File
@@ -0,0 +1,22 @@
{
"name": "p3exercise",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^16.1.4",
"express": "^4.18.2",
"mongoose": "^7.2.2",
"morgan": "^1.10.0"
},
"devDependencies": {
"nodemon": "^2.0.22"
}
}
+93
View File
@@ -0,0 +1,93 @@
require("dotenv").config();
const express = require("express");
const cors = require("cors");
const morgan = require("morgan");
const Person = require("./models/person");
const app = express();
const errorHandler = (error, req, res, next) => {
console.log(err.message);
if (err.name === "CastError")
return res.status(404).send({ error: "malformatted id" });
else if (err.name === "ValidationError")
return res.status(400).json({ error: err.message });
next(err);
};
morgan.token("type", function (req, res) {
return String(JSON.stringify(req.body));
});
// middleware to deal with same origin
app.use(cors());
// middleware to allow express to deliver html
// it is unclear to me why i cant just make a get method that deals with that
app.use(express.static("build"));
// transfprms it to jsontransfprms it to json
app.use(express.json());
// adding additional information on request
app.use(
morgan(":method :url :status :res[content-length] - :response-time ms :type")
);
app.use(errorHandler);
app.get("/api/persons", (req, res, next) => {
Person.find({})
.then((persons) => {
res.json(persons);
})
.catch((err) => next(err));
});
/* currently not used
const date = new Date();
app.get("/api/info", (req, res) => {
res.send(`Phonebook has info for ${data.length} persons <br />${date}`);
});
*/
app.get("/api/persons/:id", (req, res, next) => {
Person.findById(req.params.id)
.then((person) => {
if (person) res.json(person);
else res.status(404).end();
})
.catch((err) => next(err));
});
app.post("/api/persons", (req, res, next) => {
const body = req.body;
const person = new Person({
name: body.name,
number: body.number,
id: Math.floor(Math.random() * 1000),
});
person
.save()
.then((savedPerson) => {
res.json(savedPerson);
})
.catch((err) => next(err));
});
app.put("/api/persons/:id", (req, res, next) => {
const { name, number } = req.body;
Person.findOneAndUpdate(
{ id: req.params.id },
{ name, number },
{ new: true, runValidators: true, context: "query" }
)
.then((updatedPerson) => {
res.json(updatedPerson);
})
.catch((err) => next(err));
});
app.delete("/api/persons/:id", (req, res, next) => {
Person.findByIdAndRemove(req.params.id)
.then((result) => {
console.log("result:", result);
res.status(204).end();
})
.catch((err) => next(err));
});
const PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
+8
View File
@@ -0,0 +1,8 @@
#! /usr/bin/bash
rm -r ./frontend/build
echo -n "removed build from frontend"
npm run build --prefix frontend
echo -n "made new build"
cp -r ./frontend/build ./backend
echo -n "copied build to frontend"
@@ -0,0 +1,13 @@
{
"files": {
"main.css": "/static/css/main.305410ed.css",
"main.js": "/static/js/main.dde63dc0.js",
"index.html": "/index.html",
"main.305410ed.css.map": "/static/css/main.305410ed.css.map",
"main.dde63dc0.js.map": "/static/js/main.dde63dc0.js.map"
},
"entrypoints": [
"static/css/main.305410ed.css",
"static/js/main.dde63dc0.js"
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

+1
View File
@@ -0,0 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><script defer="defer" src="/static/js/main.dde63dc0.js"></script><link href="/static/css/main.305410ed.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

+25
View File
@@ -0,0 +1,25 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
+3
View File
@@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
@@ -0,0 +1,2 @@
.error{color:red}.error,.normal{background:#d3d3d3;border-radius:5px;border-style:solid;font-size:20px;margin-bottom:10px;padding:10px}.normal{color:green}
/*# sourceMappingURL=main.305410ed.css.map*/
@@ -0,0 +1 @@
{"version":3,"file":"static/css/main.305410ed.css","mappings":"AAAA,OACE,SAOF,CACA,eAPE,kBAAqB,CAGrB,iBAAkB,CADlB,kBAAmB,CADnB,cAAe,CAIf,kBAAmB,CADnB,YAWF,CARA,QACE,WAOF","sources":["index.css"],"sourcesContent":[".error {\n color: red;\n background: lightgrey;\n font-size: 20px;\n border-style: solid;\n border-radius: 5px;\n padding: 10px;\n margin-bottom: 10px;\n}\n.normal {\n color: green;\n background: lightgrey;\n font-size: 20px;\n border-style: solid;\n border-radius: 5px;\n padding: 10px;\n margin-bottom: 10px;\n}\n"],"names":[],"sourceRoot":""}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,39 @@
/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
File diff suppressed because one or more lines are too long
+19
View File
@@ -0,0 +1,19 @@
{
"persons": [
{
"name": "dsdsd",
"number": "sdsdsds",
"id": 6
},
{
"name": "dfadf",
"number": "dafasdfa",
"id": 7
},
{
"name": "sdfadfadaf",
"number": "adfadfadsf",
"id": 9
}
]
}
File diff suppressed because it is too large Load Diff
+44
View File
@@ -0,0 +1,44 @@
{
"name": "p1",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.4.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"server": "npx json-server --port 3001 --watch db.json"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"json-serve": "^0.1.0"
},
"proxy": "http://localhost:3001"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

+43
View File
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

@@ -0,0 +1,25 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
+3
View File
@@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
+44
View File
@@ -0,0 +1,44 @@
import Persons from "./components/Persons";
import Filter from "./components/Filter";
import PersonForm from "./components/PersonForm";
import Notification from "./components/Notification";
import { useState, useEffect } from "react";
import personServices from "./services/persons";
const App = () => {
const [persons, setPersons] = useState([]);
const [filter, setFilter] = useState("");
const [message, setMessage] = useState(null);
useEffect(() => {
personServices.getAll().then((response) => setPersons(response.data));
}, []);
function displayMessage(message, type = "normal") {
setMessage({message,type});
setTimeout(() => {
setMessage(null);
}, 5000);
}
return (
<div>
<h2>Phonebook</h2>
<Notification message={message} />
<Filter persons={persons} filter={filter} setFilter={setFilter} />
<h2>add a new</h2>
<PersonForm
persons={persons}
setPersons={setPersons}
displayMessage={displayMessage}
/>
<h2>Numbers</h2>
<Persons
persons={persons.filter((el) =>
el.name.toLowerCase().includes(filter.toLowerCase())
)}
setPersons={setPersons}
/>
</div>
);
};
export default App;
@@ -0,0 +1,19 @@
function Course({ course }) {
const total = course.parts.reduce((acc, curr) => acc + curr.exercises, 0);
return (
<>
<h1>{course.name}</h1>
<ul>
{course.parts.map((c) => (
<li key={c.id}>
{c.name} {c.exercises}
</li>
))}
<li>
<b>total of</b> {total} <b>exercises</b>
</li>
</ul>
</>
);
}
export default Course;
@@ -0,0 +1,12 @@
function Filter({ filter, setFilter}) {
function onFilter(e) {
setFilter(e.target.value);
}
return (
<div>
filter shown with <input value={filter} onChange={onFilter} />
</div>
);
}
export default Filter;
@@ -0,0 +1,5 @@
const Notification= ({message}) => {
if (message === null) return null;
return <div className={message.type}>{message.message}</div>;
};
export default Notification
@@ -0,0 +1,60 @@
import { useState } from "react";
import personServices from "../services/persons";
function PersonForm({ persons, setPersons, displayMessage }) {
const [newName, setNewName] = useState("");
const [newNumber, setNewNumber] = useState("");
function onAddPerson(e) {
e.preventDefault();
const newPerson = { name: newName, number: newNumber };
const id = persons.find((el) => el.name === newName)?.id;
if (id) {
personServices
.update(id, newPerson)
.then(() => {
setPersons(
persons.map((person) => (person.id !== id ? person : newPerson))
);
displayMessage("Number changed");
})
.catch((err) => {
console.error(err.message);
displayMessage("Number has already been removed", "error");
});
} else {
personServices
.create(newPerson)
.then(() => {
setPersons([...persons, newPerson]);
displayMessage("Person Added");
})
.catch((error) => {
console.log(error.response.data)
displayMessage('Validation Error', "error");
});
}
setNewName("");
setNewNumber("");
}
return (
<form onSubmit={onAddPerson}>
<div>
name:{" "}
<input value={newName} onChange={(e) => setNewName(e.target.value)} />
</div>
<div>
number:{" "}
<input
value={newNumber}
onChange={(e) => setNewNumber(e.target.value)}
/>
</div>
<div>
<button type="submit">add</button>
</div>
</form>
);
}
export default PersonForm;
@@ -0,0 +1,20 @@
import personServices from "../services/persons";
function Persons({ persons, setPersons }) {
function onDelete(id) {
personServices
.remove(id)
.then(setPersons(persons.filter((pred) => pred.id != id)));
}
return (
<ul>
{persons.map((person, index) => (
<li key={index}>
{person.name} {person.number}{" "}
<button onClick={() => onDelete(person.id)}>delete</button>
</li>
))}
</ul>
);
}
export default Persons;
+18
View File
@@ -0,0 +1,18 @@
.error {
color: red;
background: lightgrey;
font-size: 20px;
border-style: solid;
border-radius: 5px;
padding: 10px;
margin-bottom: 10px;
}
.normal {
color: green;
background: lightgrey;
font-size: 20px;
border-style: solid;
border-radius: 5px;
padding: 10px;
margin-bottom: 10px;
}
+27
View File
@@ -0,0 +1,27 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import './index.css'
import App from './App'
const notes = [
{
id: 1,
content: 'HTML is easy',
important: true
},
{
id: 2,
content: 'Browser can execute only JavaScript',
important: false
},
{
id: 3,
content: 'GET and POST are the most important methods of HTTP protocol',
important: true
}
]
ReactDOM.createRoot(document.getElementById('root')).render(
<App notes={notes} />
)
@@ -0,0 +1,15 @@
import axios from "axios";
const baseUrl = "/api/persons/";
const getAll = () => axios.get(baseUrl);
const create = (newPerson) => axios.post(baseUrl, newPerson);
const remove = (id) => axios.delete(baseUrl.concat(id.toString()));
const update = (id, newPerson) => axios.put(`${baseUrl}${id}`, newPerson);
export default {
getAll: getAll,
create: create,
remove: remove,
update: update,
};
+78
View File
@@ -0,0 +1,78 @@
import { useState } from "react";
function Statistics({ good, bad, neutral }) {
return (
<div>
<h1>statistics</h1>
<ul>
<StatisticsLine text={"good"} value={good} />
<StatisticsLine text={"neutral"} value={neutral} />
<StatisticsLine text={"bad"} value={bad} />
<StatisticsLine text={"all"} value={bad + good + neutral} />
<StatisticsLine
text={"average"}
value={(good - bad) / (good + bad + neutral)}
/>
</ul>
</div>
);
}
function StatisticsLine({ text, value }) {
return (
<li>
{text}: {value}
</li>
);
}
function Anecdotes({ anecdotes, selected }) {
return (
<>
<div>{anecdotes[selected]}</div>
</>
);
}
const App = () => {
// save clicks of each button to its own state
const [good, setGood] = useState(0);
const [neutral, setNeutral] = useState(0);
const [bad, setBad] = useState(0);
const [selected, setSelected] = useState(0);
const [votes, setVotes] = useState(new Array(7).fill(0));
const anecdotes = [
"If it hurts, do it more often.",
"Adding manpower to a late software project makes it later!",
"The first 90 percent of the code accounts for the first 10 percent of the development time...The remaining 10 percent of the code accounts for the other 90 percent of the development time.",
"Any fool can write code that a computer can understand. Good programmers write code that humans can understand.",
"Premature optimization is the root of all evil.",
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.",
"Programming without an extremely heavy use of console.log is same as if a doctor would refuse to use x-rays or blood tests when diagnosing patients.",
"The only way to go fast, is to go well.",
];
let highest = Math.max(...votes)
function addVote() {
let newVotes = [...votes];
newVotes[selected] += 1;
setVotes(newVotes);
}
return (
<div>
<h1>give feedback</h1>
<button onClick={() => setGood(good + 1)}>good</button>
<button onClick={() => setNeutral(neutral + 1)}>neutral</button>
<button onClick={() => setBad(bad + 1)}>bad</button>
<Statistics good={good} bad={bad} neutral={neutral} />
<Anecdotes anecdotes={anecdotes} selected={selected} />
<h1>has {votes[selected]} votes</h1>
<button onClick={() => addVote()}>vote</button>
<button onClick={() => setSelected(Math.floor(Math.random() * 7))}>
next anecdote{" "}
</button>
<h1>Is the most liked</h1>
<Anecdotes anecdotes={anecdotes} selected={Math.max(...votes)}/>
</div>
);
};
export default App;
+6
View File
@@ -0,0 +1,6 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
ReactDOM.createRoot(document.getElementById('root')).render(<App />)
+16
View File
@@ -0,0 +1,16 @@
#! /usr/bin/bash
echo -n "1 for get All, 2 for get with id, 3 for create, 4 for delete "
read action
if [[ $action == 1 ]]; then
curl http://localhost:3001/api/persons | json_pp -json_opt pretty,canonical
elif [[ $action == 2 ]]; then
echo -n "gib id "
read id
curl http://localhost:3001/api/persons/${id} | json_pp -json_opt pretty,canonical
elif [[ $action == 3 ]]; then
curl -H "Content-Type: application/json" -X POST -d '{"name":"xyz","number":"xyz"}' http://localhost:3001/api/persons | json_pp -json_opt pretty,canonical
elif [[ $action == 4 ]]; then
echo -n "gib id "
read id
curl -H "Content-Type: application/json" -X DELETE http://localhost:3001/api/persons/6482b803a270efb823a3cfb0 | json_pp -json_opt pretty,canonical
fi