├── vite.config.js
├── .gitignore
├── index.html
├── .eslintrc.cjs
├── src
├── App.css
├── main.jsx
├── App.jsx
├── components
│ ├── Users.jsx
│ └── Update.jsx
├── index.css
└── assets
│ └── react.svg
├── package.json
└── public
└── vite.svg
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: { browser: true, es2020: true },
3 | extends: [
4 | 'eslint:recommended',
5 | 'plugin:react/recommended',
6 | 'plugin:react/jsx-runtime',
7 | 'plugin:react-hooks/recommended',
8 | ],
9 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
10 | settings: { react: { version: '18.2' } },
11 | plugins: ['react-refresh'],
12 | rules: {
13 | 'react-refresh/only-export-components': 'warn',
14 | },
15 | }
16 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "simple-crud-client",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "localforage": "^1.10.0",
14 | "match-sorter": "^6.3.1",
15 | "react": "^18.2.0",
16 | "react-dom": "^18.2.0",
17 | "react-router-dom": "^6.11.0",
18 | "sort-by": "^1.2.0"
19 | },
20 | "devDependencies": {
21 | "@types/react": "^18.0.28",
22 | "@types/react-dom": "^18.0.11",
23 | "@vitejs/plugin-react": "^4.0.0",
24 | "eslint": "^8.38.0",
25 | "eslint-plugin-react": "^7.32.2",
26 | "eslint-plugin-react-hooks": "^4.6.0",
27 | "eslint-plugin-react-refresh": "^0.3.4",
28 | "vite": "^4.3.2"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './index.css'
5 | import {
6 | createBrowserRouter,
7 | RouterProvider,
8 | } from "react-router-dom";
9 | import Users from './components/Users.jsx';
10 | import Update from './components/Update.jsx';
11 |
12 | const router = createBrowserRouter([
13 | {
14 | path: "/",
15 | element: ,
16 | },
17 | {
18 | path:'/users',
19 | element: ,
20 | loader: () => fetch('http://localhost:5000/users')
21 | },
22 | {
23 | path: '/update/:id',
24 | element: ,
25 | loader: ({params}) => fetch(`http://localhost:5000/users/${params.id}`)
26 | }
27 | ]);
28 |
29 | ReactDOM.createRoot(document.getElementById('root')).render(
30 |
31 |
32 | ,
33 | )
34 |
--------------------------------------------------------------------------------
/src/App.jsx:
--------------------------------------------------------------------------------
1 | import './App.css'
2 |
3 | function App() {
4 | const handleAddUser = event => {
5 | event.preventDefault();
6 | const form = event.target;
7 | const name = form.name.value;
8 | const email = form.email.value;
9 | const user = { name, email };
10 | console.log(user);
11 |
12 | fetch('http://localhost:5000/users', {
13 | method: 'POST',
14 | headers: {
15 | 'content-type': 'application/json'
16 | },
17 | body: JSON.stringify(user)
18 | })
19 | .then(res => res.json())
20 | .then(data => {
21 | console.log(data);
22 | if (data.insertedId) {
23 | alert('Users added successfully');
24 | form.reset();
25 | }
26 | })
27 | }
28 |
29 | return (
30 | <>
31 | Simple CRUD
32 |
39 | >
40 | )
41 | }
42 |
43 | export default App
44 |
--------------------------------------------------------------------------------
/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/Users.jsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | import { Link, useLoaderData } from 'react-router-dom';
3 |
4 | const Users = () => {
5 |
6 | const loadedUsers = useLoaderData();
7 | const [users, setUsers] = useState(loadedUsers);
8 |
9 | const handleDelete = _id =>{
10 | console.log( 'delete', _id);
11 | fetch(`http://localhost:5000/users/${_id}`, {
12 | method: 'DELETE'
13 | })
14 | .then(res=> res.json())
15 | .then(data => {
16 | console.log(data);
17 | if(data.deletedCount>0){
18 | alert('deleted successfully');
19 | const remaining = users.filter(user => user._id !== _id);
20 | setUsers(remaining);
21 | }
22 | })
23 | }
24 |
25 | return (
26 |
27 |
{users.length}
28 |
29 | {
30 | users.map(user =>
{user.name} : {user.email} {user._id}
33 |
34 |
35 |
36 |
)
39 | }
40 |
41 |
42 | );
43 | };
44 |
45 | export default Users;
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | :root {
2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
3 | line-height: 1.5;
4 | font-weight: 400;
5 |
6 | color-scheme: light dark;
7 | color: rgba(255, 255, 255, 0.87);
8 | background-color: #242424;
9 |
10 | font-synthesis: none;
11 | text-rendering: optimizeLegibility;
12 | -webkit-font-smoothing: antialiased;
13 | -moz-osx-font-smoothing: grayscale;
14 | -webkit-text-size-adjust: 100%;
15 | }
16 |
17 | a {
18 | font-weight: 500;
19 | color: #646cff;
20 | text-decoration: inherit;
21 | }
22 | a:hover {
23 | color: #535bf2;
24 | }
25 |
26 | body {
27 | margin: 0;
28 | display: flex;
29 | place-items: center;
30 | min-width: 320px;
31 | min-height: 100vh;
32 | }
33 |
34 | h1 {
35 | font-size: 3.2em;
36 | line-height: 1.1;
37 | }
38 |
39 | button {
40 | border-radius: 8px;
41 | border: 1px solid transparent;
42 | padding: 0.6em 1.2em;
43 | font-size: 1em;
44 | font-weight: 500;
45 | font-family: inherit;
46 | background-color: #1a1a1a;
47 | cursor: pointer;
48 | transition: border-color 0.25s;
49 | }
50 | button:hover {
51 | border-color: #646cff;
52 | }
53 | button:focus,
54 | button:focus-visible {
55 | outline: 4px auto -webkit-focus-ring-color;
56 | }
57 |
58 | @media (prefers-color-scheme: light) {
59 | :root {
60 | color: #213547;
61 | background-color: #ffffff;
62 | }
63 | a:hover {
64 | color: #747bff;
65 | }
66 | button {
67 | background-color: #f9f9f9;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/components/Update.jsx:
--------------------------------------------------------------------------------
1 | import { useLoaderData } from 'react-router-dom';
2 |
3 | const Update = () => {
4 | const loadedUser = useLoaderData();
5 |
6 | const handleUpdate = event => {
7 | event.preventDefault();
8 | const form = event.target;
9 | const name = form.name.value;
10 | const email = form.email.value;
11 | console.log(name, email);
12 | const updatedUser = { name, email };
13 |
14 | fetch(`http://localhost:5000/users/${loadedUser._id}`, {
15 | method: 'PUT',
16 | headers: {
17 | 'content-type': 'application/json'
18 | },
19 | body: JSON.stringify(updatedUser)
20 | })
21 | .then(res => res.json())
22 | .then(data => {
23 | console.log(data);
24 | if (data.modifiedCount > 0) {
25 | alert('user updated successfully')
26 | }
27 | })
28 | }
29 |
30 | return (
31 |
32 |
Update information of {loadedUser.name}
33 |
40 |
41 | );
42 | };
43 |
44 | export default Update;
--------------------------------------------------------------------------------
/src/assets/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------