├── .gitignore
├── README.md
├── db.json
├── package-lock.json
├── package.json
├── public
├── favicon.ico
└── index.html
├── src
├── App.css
├── App.js
├── index.css
├── index.js
└── pages
│ ├── Home.js
│ ├── Navbar.js
│ └── user
│ ├── Add.js
│ ├── Edit.js
│ └── Users.js
└── tailwind.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CRUD
2 |
3 |
4 | A React CRUD App using Tailwind CSS, Axios, React-Router-Dom and Json-Server.
5 |
6 |
7 | We've uesd the fake JSON-server for our fake APIs and use React Axios package to perform HTTP Requests in react.
8 |
9 |
10 | We follow the RESTful API convention (GET, POST, PUT, DELETE) and see how easily we do CREATE, READ, UPDATE and DELETE operations on our User Details.
11 |
12 |
13 | We've learned so far about how to send data to server and get the response back from server.
14 |
15 |
16 | We've seen how we can update our React state with the data received from the server and render our UI with that updated data.
17 |
--------------------------------------------------------------------------------
/db.json:
--------------------------------------------------------------------------------
1 | {
2 | "users": [
3 | {
4 | "name": "Ervin Howell",
5 | "email": "Ervin@melissa.tv",
6 | "phone": "010-692-6593 x09125",
7 | "id": 2
8 | },
9 | {
10 | "id": 3,
11 | "name": "Clementine Bauch",
12 | "username": "Samantha",
13 | "email": "Nathan@yesenia.net",
14 | "address": {
15 | "street": "Douglas Extension",
16 | "suite": "Suite 847",
17 | "city": "McKenziehaven",
18 | "zipcode": "59590-4157",
19 | "geo": {
20 | "lat": "-68.6102",
21 | "lng": "-47.0653"
22 | }
23 | },
24 | "phone": "1-463-123-4447",
25 | "website": "ramiro.info",
26 | "company": {
27 | "name": "Romaguera-Jacobson",
28 | "catchPhrase": "Face to face bifurcated interface",
29 | "bs": "e-enable strategic applications"
30 | }
31 | },
32 | {
33 | "id": 4,
34 | "name": "Patricia Lebsack",
35 | "username": "Karianne",
36 | "email": "Julianne.OConner@kory.org",
37 | "address": {
38 | "street": "Hoeger Mall",
39 | "suite": "Apt. 692",
40 | "city": "South Elvis",
41 | "zipcode": "53919-4257",
42 | "geo": {
43 | "lat": "29.4572",
44 | "lng": "-164.2990"
45 | }
46 | },
47 | "phone": "493-170-9623 x156",
48 | "website": "kale.biz",
49 | "company": {
50 | "name": "Robel-Corkery",
51 | "catchPhrase": "Multi-tiered zero tolerance productivity",
52 | "bs": "transition cutting-edge web services"
53 | }
54 | },
55 | {
56 | "id": 5,
57 | "name": "Chelsey Dietrich",
58 | "username": "Kamren",
59 | "email": "Lucio_Hettinger@annie.ca",
60 | "address": {
61 | "street": "Skiles Walks",
62 | "suite": "Suite 351",
63 | "city": "Roscoeview",
64 | "zipcode": "33263",
65 | "geo": {
66 | "lat": "-31.8129",
67 | "lng": "62.5342"
68 | }
69 | },
70 | "phone": "(254)954-1289",
71 | "website": "demarco.info",
72 | "company": {
73 | "name": "Keebler LLC",
74 | "catchPhrase": "User-centric fault-tolerant solution",
75 | "bs": "revolutionize end-to-end systems"
76 | }
77 | },
78 | {
79 | "id": 6,
80 | "name": "Mrs. Dennis Schulist",
81 | "username": "Leopoldo_Corkery",
82 | "email": "Karley_Dach@jasper.info",
83 | "address": {
84 | "street": "Norberto Crossing",
85 | "suite": "Apt. 950",
86 | "city": "South Christy",
87 | "zipcode": "23505-1337",
88 | "geo": {
89 | "lat": "-71.4197",
90 | "lng": "71.7478"
91 | }
92 | },
93 | "phone": "1-477-935-8478 x6430",
94 | "website": "ola.org",
95 | "company": {
96 | "name": "Considine-Lockman",
97 | "catchPhrase": "Synchronised bottom-line interface",
98 | "bs": "e-enable innovative applications"
99 | }
100 | },
101 | {
102 | "id": 7,
103 | "name": "Kurtis Weissnat",
104 | "username": "Elwyn.Skiles",
105 | "email": "Telly.Hoeger@billy.biz",
106 | "address": {
107 | "street": "Rex Trail",
108 | "suite": "Suite 280",
109 | "city": "Howemouth",
110 | "zipcode": "58804-1099",
111 | "geo": {
112 | "lat": "24.8918",
113 | "lng": "21.8984"
114 | }
115 | },
116 | "phone": "210.067.6132",
117 | "website": "elvis.io",
118 | "company": {
119 | "name": "Johns Group",
120 | "catchPhrase": "Configurable multimedia task-force",
121 | "bs": "generate enterprise e-tailers"
122 | }
123 | },
124 | {
125 | "name": "Curt Hendricks",
126 | "email": "cobolt@codename.com",
127 | "phone": "0000-22-0000",
128 | "id": 8
129 | }
130 | ]
131 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "crud",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.16.3",
7 | "@testing-library/react": "^12.1.4",
8 | "@testing-library/user-event": "^13.5.0",
9 | "axios": "^0.26.1",
10 | "json-server": "^0.17.0",
11 | "react": "^18.0.0",
12 | "react-dom": "^18.0.0",
13 | "react-router-dom": "^6.3.0",
14 | "react-scripts": "5.0.0",
15 | "web-vitals": "^2.1.4"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "json-server": "json-server --watch db.json --port 3001",
20 | "build": "react-scripts build",
21 | "test": "react-scripts test",
22 | "eject": "react-scripts eject"
23 | },
24 | "eslintConfig": {
25 | "extends": [
26 | "react-app",
27 | "react-app/jest"
28 | ]
29 | },
30 | "browserslist": {
31 | "production": [
32 | ">0.2%",
33 | "not dead",
34 | "not op_mini all"
35 | ],
36 | "development": [
37 | "last 1 chrome version",
38 | "last 1 firefox version",
39 | "last 1 safari version"
40 | ]
41 | },
42 | "devDependencies": {
43 | "autoprefixer": "^10.4.4",
44 | "postcss": "^8.4.12",
45 | "tailwindcss": "^3.0.23"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/geeky-mind/CRUD/dd8feeaeab5f64559c0b0eb103661060778748f0/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | REACT
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | height: 40vmin;
7 | pointer-events: none;
8 | }
9 |
10 | @media (prefers-reduced-motion: no-preference) {
11 | .App-logo {
12 | animation: App-logo-spin infinite 20s linear;
13 | }
14 | }
15 |
16 | .App-header {
17 | background-color: #282c34;
18 | min-height: 100vh;
19 | display: flex;
20 | flex-direction: column;
21 | align-items: center;
22 | justify-content: center;
23 | font-size: calc(10px + 2vmin);
24 | color: white;
25 | }
26 |
27 | .App-link {
28 | color: #61dafb;
29 | }
30 |
31 | @keyframes App-logo-spin {
32 | from {
33 | transform: rotate(0deg);
34 | }
35 | to {
36 | transform: rotate(360deg);
37 | }
38 | }
39 |
40 | @tailwind base;
41 | @tailwind components;
42 | @tailwind utilities;
43 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import { Route, Routes } from 'react-router-dom';
2 | import './App.css';
3 | import Home from './pages/Home';
4 | import Navbar from './pages/Navbar';
5 | import Add from './pages/user/Add';
6 | import Edit from './pages/user/Edit';
7 | import Users from './pages/user/Users';
8 |
9 | function App() {
10 | return (
11 |
12 |
13 |
14 | } />
15 | } />
16 | } />
17 | } />
18 | } />
19 |
20 |
21 | );
22 | }
23 |
24 | export default App;
25 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import "./index.css";
4 | import App from "./App";
5 | import { BrowserRouter } from "react-router-dom";
6 |
7 | const root = ReactDOM.createRoot(document.getElementById("root"));
8 | root.render(
9 |
10 |
11 |
12 |
13 |
14 | );
--------------------------------------------------------------------------------
/src/pages/Home.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import React, { useEffect, useState } from "react";
3 | import { Link } from "react-router-dom";
4 |
5 | function Home() {
6 | const [users, setUsers] = useState([]);
7 |
8 | function loadUsers() {
9 | axios.get("http://localhost:3001/users").then((res) => {
10 | setUsers(res.data.reverse());
11 | });
12 | }
13 |
14 | useEffect(() => {
15 | loadUsers();
16 | }, []);
17 |
18 | function deleteUser(id) {
19 | axios.delete(`http://localhost:3001/users/${id}`).then(loadUsers());
20 | }
21 |
22 | return (
23 | <>
24 |
25 |
DATA TABLE
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
37 | #
38 | |
39 |
43 | Name
44 | |
45 |
49 | Email
50 | |
51 |
55 | Phone
56 | |
57 |
61 | Action
62 | |
63 |
64 |
65 |
66 | {users.map((data, index) => (
67 |
71 |
72 | {index + 1}
73 | |
74 |
75 | {data.name}
76 | |
77 |
78 | {data.email}
79 | |
80 |
81 | {data.phone}
82 | |
83 |
84 |
88 | VIew
89 |
90 |
94 | Edit
95 |
96 | deleteUser(data.id)}
98 | to={"#"}
99 | className="bg-red-600 text-white px-6 py-2 rounded-lg"
100 | >
101 | Delete
102 |
103 | |
104 |
105 | ))}
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 | >
114 | );
115 | }
116 |
117 | export default Home;
118 |
--------------------------------------------------------------------------------
/src/pages/Navbar.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router-dom'
3 |
4 | function Navbar() {
5 | return (
6 | <>
7 |
8 | CRUD
9 | Add Users
11 |
12 | >
13 | )
14 | }
15 |
16 | export default Navbar
--------------------------------------------------------------------------------
/src/pages/user/Add.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import React, { useState } from "react";
3 | import { useNavigate } from "react-router-dom";
4 |
5 | function Add() {
6 | const [name, setName] = useState("");
7 | const [email, setEmail] = useState("");
8 | const [phone, setPhone] = useState("");
9 |
10 | const navigate = useNavigate();
11 | const data = {
12 | name: name,
13 | email: email,
14 | phone: phone,
15 | };
16 |
17 | function submitForm(e) {
18 | e.preventDefault();
19 | axios.post("http://localhost:3001/users", data).then(navigate("/"));
20 | }
21 | return (
22 |
23 |
ADD USER
24 |
54 |
55 | );
56 | }
57 |
58 | export default Add;
59 |
--------------------------------------------------------------------------------
/src/pages/user/Edit.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import React, { useEffect, useState } from "react";
3 | import { useNavigate, useParams } from "react-router-dom";
4 |
5 | function Add() {
6 | const [name, setName] = useState("");
7 | const [email, setEmail] = useState("");
8 | const [phone, setPhone] = useState("");
9 |
10 | const { id } = useParams();
11 |
12 | useEffect(() => {
13 | axios.get(`http://localhost:3001/users/${id}`).then((res) => {
14 | setName(res.data.name);
15 | setEmail(res.data.email);
16 | setPhone(res.data.phone);
17 | });
18 | }, []);
19 |
20 | const navigate = useNavigate();
21 |
22 | const data = {
23 | name: name,
24 | email: email,
25 | phone: phone,
26 | };
27 |
28 | function Update(e) {
29 | e.preventDefault();
30 | axios.put(`http://localhost:3001/users/${id}`, data).then(navigate("/"));
31 | }
32 | return (
33 |
34 |
User Details
35 |
65 |
66 | );
67 | }
68 |
69 | export default Add;
70 |
--------------------------------------------------------------------------------
/src/pages/user/Users.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import React, { useEffect, useState } from "react";
3 | import { Link, useParams } from "react-router-dom";
4 |
5 | function Users() {
6 | const { id } = useParams();
7 |
8 | const [user, setUser] = useState([]);
9 |
10 | useEffect(() => {
11 | axios.get(`http://localhost:3001/users/${id}`).then((res) => {
12 | setUser(res.data);
13 | });
14 | }, []);
15 |
16 | console.log(user);
17 | return (
18 | <>
19 |
20 |
24 | Back To Home
25 |
26 | {user && (
27 |
28 |
29 |
30 | Name
31 |
32 |
33 | Email
34 |
35 |
36 | Phone
37 |
38 |
39 |
40 |
41 | {user.name}
42 |
43 |
44 | {user.email}
45 |
46 |
47 | {user.phone}
48 |
49 |
50 |
51 | )}
52 |
53 | >
54 | );
55 | }
56 |
57 | export default Users;
58 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | content: ["./src/**/*.{html,js}"],
3 | theme: {
4 | screens: {
5 | '2xl': {'max': '1535px'},
6 | // => @media (max-width: 1535px) { ... }
7 |
8 | 'xl': {'max': '1279px'},
9 | // => @media (max-width: 1279px) { ... }
10 |
11 | 'lg': {'max': '1023px'},
12 | // => @media (max-width: 1023px) { ... }
13 |
14 | 'md': {'max': '767px'},
15 | // => @media (max-width: 767px) { ... }
16 |
17 | 'sm': {'max': '639px'},
18 | // => @media (max-width: 639px) { ... }
19 | }
20 | },
21 | plugins: [],
22 | }
23 |
--------------------------------------------------------------------------------