Changed Code and fetch data from json api
This commit is contained in:
parent
38335cef91
commit
3426fb7c97
|
@ -1,24 +1,14 @@
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useParams, useNavigate } from "react-router-dom";
|
import { useParams, useNavigate, useLocation } from "react-router-dom";
|
||||||
import { useForm, Controller } from "react-hook-form";
|
import { useForm, Controller } from "react-hook-form";
|
||||||
|
|
||||||
const EditUser = () => {
|
const EditUser = () => {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const location = useLocation();
|
||||||
|
const [users, setUsers] = useState(location.state?.users || []);
|
||||||
|
|
||||||
const [users, setUsers] = useState([]);
|
const { control, handleSubmit, reset, formState: { errors } } = useForm({
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const storedUsers = JSON.parse(localStorage.getItem("users")) || [];
|
|
||||||
setUsers(storedUsers);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const {
|
|
||||||
control,
|
|
||||||
handleSubmit,
|
|
||||||
reset,
|
|
||||||
formState: { errors },
|
|
||||||
} = useForm({
|
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: "",
|
name: "",
|
||||||
email: "",
|
email: "",
|
||||||
|
@ -28,112 +18,87 @@ const EditUser = () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (id && id !== "new") {
|
if (users.length === 0) {
|
||||||
const existingUser = users.find((user) => user.id === parseInt(id));
|
const fetchUsers = async () => {
|
||||||
if (existingUser) {
|
const response = await fetch("https://jsonplaceholder.typicode.com/users");
|
||||||
reset(existingUser);
|
const data = await response.json();
|
||||||
}
|
setUsers(data);
|
||||||
|
};
|
||||||
|
fetchUsers();
|
||||||
}
|
}
|
||||||
}, [id, users, reset]);
|
}, [users]);
|
||||||
|
|
||||||
|
const user = users.find((user) => user.id === parseInt(id));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (user) {
|
||||||
|
reset(user);
|
||||||
|
}
|
||||||
|
}, [user, reset]);
|
||||||
|
|
||||||
const onSubmit = (data) => {
|
const onSubmit = (data) => {
|
||||||
let updatedUsers;
|
let updatedUsers;
|
||||||
if (id === "new") {
|
if (id === "new") {
|
||||||
const newUser = { ...data, id: users.length + 1 };
|
const newUser = { ...data, id: users.length + 1 };
|
||||||
updatedUsers = [...users, newUser];
|
updatedUsers = [...users, newUser];
|
||||||
alert("User added successfully!");
|
alert("User added successfully!");
|
||||||
} else {
|
} else {
|
||||||
updatedUsers = users.map((user) =>
|
updatedUsers = users.map((u) =>
|
||||||
user.id === parseInt(id) ? { ...data, id: user.id } : user
|
u.id === parseInt(id) ? { ...data, id: u.id } : u
|
||||||
);
|
);
|
||||||
alert("User updated successfully!");
|
alert("User updated successfully!");
|
||||||
}
|
}
|
||||||
|
|
||||||
setUsers(updatedUsers);
|
setUsers(updatedUsers);
|
||||||
localStorage.setItem("users", JSON.stringify(updatedUsers));
|
navigate("/", { state: { users: updatedUsers } });
|
||||||
navigate("/");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
const updatedUsers = users.filter((user) => user.id !== parseInt(id));
|
const updatedUsers = users.filter((user) => user.id !== parseInt(id));
|
||||||
setUsers(updatedUsers);
|
setUsers(updatedUsers);
|
||||||
localStorage.setItem("users", JSON.stringify(updatedUsers));
|
|
||||||
alert(`User with ID ${id} deleted.`);
|
alert(`User with ID ${id} deleted.`);
|
||||||
navigate("/");
|
navigate("/", { state: { users: updatedUsers } });
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="form-container">
|
<div className="form-container">
|
||||||
<h1>{id === "new" ? "Add" : "Edit"} User</h1>
|
<h1>{id === "new" ? "Add" : "Edit"} User</h1>
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
{/* Form Fields */}
|
<div>
|
||||||
<div className="form-group">
|
|
||||||
<label>Name</label>
|
<label>Name</label>
|
||||||
<Controller
|
<Controller
|
||||||
name="name"
|
name="name"
|
||||||
control={control}
|
control={control}
|
||||||
rules={{ required: "Name is required." }}
|
rules={{ required: "Name is required" }}
|
||||||
render={({ field }) => (
|
render={({ field }) => <input {...field} />}
|
||||||
<input {...field} className={errors.name ? "error-input" : ""} />
|
|
||||||
)}
|
|
||||||
/>
|
/>
|
||||||
{errors.name && <span>{errors.name.message}</span>}
|
{errors.name && <p>{errors.name.message}</p>}
|
||||||
</div>
|
</div>
|
||||||
<div className="form-group">
|
<div>
|
||||||
<label>Email</label>
|
<label>Email</label>
|
||||||
<Controller
|
<Controller
|
||||||
name="email"
|
name="email"
|
||||||
control={control}
|
control={control}
|
||||||
rules={{
|
rules={{ required: "Email is required" }}
|
||||||
required: "Email is required.",
|
render={({ field }) => <input {...field} />}
|
||||||
pattern: {
|
|
||||||
value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
|
|
||||||
message: "Invalid email format.",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
render={({ field }) => (
|
|
||||||
<input {...field} className={errors.email ? "error-input" : ""} />
|
|
||||||
)}
|
|
||||||
/>
|
/>
|
||||||
{errors.email && <span>{errors.email.message}</span>}
|
{errors.email && <p>{errors.email.message}</p>}
|
||||||
</div>
|
</div>
|
||||||
<div className="form-group">
|
<div>
|
||||||
<label>Phone</label>
|
<label>Phone</label>
|
||||||
<Controller
|
<Controller
|
||||||
name="phone"
|
name="phone"
|
||||||
control={control}
|
control={control}
|
||||||
rules={{
|
render={({ field }) => <input {...field} />}
|
||||||
required: "Phone number is required.",
|
|
||||||
pattern: {
|
|
||||||
value: /^[0-9]{10}$/,
|
|
||||||
message: "Phone number must be 10 digits.",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
render={({ field }) => (
|
|
||||||
<input {...field} className={errors.phone ? "error-input" : ""} />
|
|
||||||
)}
|
|
||||||
/>
|
/>
|
||||||
{errors.phone && <span>{errors.phone.message}</span>}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="form-group">
|
<div>
|
||||||
<label>Website</label>
|
<label>Website</label>
|
||||||
<Controller
|
<Controller
|
||||||
name="website"
|
name="website"
|
||||||
control={control}
|
control={control}
|
||||||
rules={{
|
render={({ field }) => <input {...field} />}
|
||||||
pattern: {
|
|
||||||
value:
|
|
||||||
/^(https?:\/\/)?([\w\d\-_]+\.)+[\w\d\-_]+(\/[\w\d\-_.?&=]*)*\/?$/,
|
|
||||||
message: "Invalid website URL.",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
render={({ field }) => (
|
|
||||||
<input
|
|
||||||
{...field}
|
|
||||||
className={errors.website ? "error-input" : ""}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
/>
|
||||||
{errors.website && <span>{errors.website.message}</span>}
|
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" className="submit-button">
|
<button type="submit" className="submit-button">
|
||||||
Save
|
Save
|
||||||
|
|
|
@ -1,29 +1,34 @@
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useParams, useNavigate } from "react-router-dom";
|
import { useParams, useNavigate, useLocation } from "react-router-dom";
|
||||||
|
|
||||||
const UserDetails = () => {
|
const UserDetails = () => {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
const [users, setUsers] = useState([]);
|
const [users, setUsers] = useState(location.state?.users || []);
|
||||||
|
const [user, setUser] = useState(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const storedUsers = JSON.parse(localStorage.getItem("users")) || [];
|
if (users.length > 0) {
|
||||||
setUsers(storedUsers);
|
const foundUser = users.find((user) => user.id === parseInt(id));
|
||||||
}, []);
|
setUser(foundUser);
|
||||||
|
} else {
|
||||||
useEffect(() => {
|
const fetchUsers = async () => {
|
||||||
localStorage.setItem("users", JSON.stringify(users));
|
const response = await fetch("https://jsonplaceholder.typicode.com/users");
|
||||||
}, [users]);
|
const data = await response.json();
|
||||||
|
setUsers(data);
|
||||||
const userId = parseInt(id, 10);
|
const foundUser = data.find((user) => user.id === parseInt(id));
|
||||||
const user = users.find((user) => user.id === userId);
|
setUser(foundUser);
|
||||||
|
};
|
||||||
|
fetchUsers();
|
||||||
|
}
|
||||||
|
}, [id, users]);
|
||||||
|
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
const updatedUsers = users.filter((user) => user.id !== userId);
|
const updatedUsers = users.filter((u) => u.id !== parseInt(id));
|
||||||
setUsers(updatedUsers);
|
|
||||||
alert(`User with ID ${id} deleted.`);
|
alert(`User with ID ${id} deleted.`);
|
||||||
navigate("/");
|
navigate("/", { state: { users: updatedUsers } });
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
|
|
|
@ -1,34 +1,35 @@
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link, useLocation } from "react-router-dom";
|
||||||
import axios from "axios";
|
|
||||||
|
|
||||||
const UserList = () => {
|
const UserList = () => {
|
||||||
const [users, setUsers] = useState([]);
|
const location = useLocation();
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
const [users, setUsers] = useState(location.state?.users || []);
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const usersPerPage = 5;
|
const usersPerPage = 5;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const storedUsers = JSON.parse(localStorage.getItem("users")) || [];
|
if (!location.state?.users) {
|
||||||
setUsers(storedUsers);
|
const fetchUsers = async () => {
|
||||||
}, []);
|
const response = await fetch(
|
||||||
|
"https://jsonplaceholder.typicode.com/users"
|
||||||
|
);
|
||||||
|
const data = await response.json();
|
||||||
|
setUsers(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchUsers();
|
||||||
|
}
|
||||||
|
}, [location.state?.users]);
|
||||||
|
|
||||||
const handleDelete = (id) => {
|
const handleDelete = (id) => {
|
||||||
const updatedUsers = users.filter((user) => user.id !== id);
|
const updatedUsers = users.filter((user) => user.id !== id);
|
||||||
setUsers(updatedUsers);
|
setUsers(updatedUsers);
|
||||||
localStorage.setItem("users", JSON.stringify(updatedUsers));
|
|
||||||
alert(`User with ID ${id} deleted.`);
|
alert(`User with ID ${id} deleted.`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const filteredUsers = users.filter(
|
|
||||||
(user) =>
|
|
||||||
user.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
||||||
user.email.toLowerCase().includes(searchTerm.toLowerCase())
|
|
||||||
);
|
|
||||||
|
|
||||||
const indexOfLastUser = currentPage * usersPerPage;
|
const indexOfLastUser = currentPage * usersPerPage;
|
||||||
const indexOfFirstUser = indexOfLastUser - usersPerPage;
|
const indexOfFirstUser = indexOfLastUser - usersPerPage;
|
||||||
const currentUsers = filteredUsers.slice(indexOfFirstUser, indexOfLastUser);
|
const currentUsers = users.slice(indexOfFirstUser, indexOfLastUser);
|
||||||
const totalPages = Math.ceil(filteredUsers.length / usersPerPage);
|
const totalPages = Math.ceil(users.length / usersPerPage);
|
||||||
|
|
||||||
const handlePageChange = (pageNumber) => {
|
const handlePageChange = (pageNumber) => {
|
||||||
setCurrentPage(pageNumber);
|
setCurrentPage(pageNumber);
|
||||||
|
@ -37,18 +38,6 @@ const UserList = () => {
|
||||||
return (
|
return (
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<h1>User List</h1>
|
<h1>User List</h1>
|
||||||
|
|
||||||
<div className="search-container">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
placeholder="Search by name or email..."
|
|
||||||
value={searchTerm}
|
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
|
||||||
className="search-input"
|
|
||||||
/>
|
|
||||||
<button className="search-button">Search</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -69,15 +58,23 @@ const UserList = () => {
|
||||||
<td>{user.phone}</td>
|
<td>{user.phone}</td>
|
||||||
<td>{user.website}</td>
|
<td>{user.website}</td>
|
||||||
<td>
|
<td>
|
||||||
<Link to={`/user/${user.id}`} className="view-button">
|
<Link
|
||||||
|
to={`/user/${user.id}`}
|
||||||
|
className="view-button"
|
||||||
|
state={{ users }}
|
||||||
|
>
|
||||||
View
|
View
|
||||||
</Link>
|
</Link>
|
||||||
<Link to={`/edit/${user.id}`} className="edit-button">
|
<Link
|
||||||
|
to={`/edit/${user.id}`}
|
||||||
|
className="edit-button"
|
||||||
|
state={{ users }}
|
||||||
|
>
|
||||||
Edit
|
Edit
|
||||||
</Link>
|
</Link>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleDelete(user.id)}
|
|
||||||
className="delete-button"
|
className="delete-button"
|
||||||
|
onClick={() => handleDelete(user.id)}
|
||||||
>
|
>
|
||||||
Delete
|
Delete
|
||||||
</button>
|
</button>
|
||||||
|
@ -87,6 +84,7 @@ const UserList = () => {
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
{/* Pagination */}
|
||||||
<div className="pagination-container">
|
<div className="pagination-container">
|
||||||
{Array.from({ length: totalPages }, (_, index) => (
|
{Array.from({ length: totalPages }, (_, index) => (
|
||||||
<button
|
<button
|
||||||
|
@ -101,11 +99,9 @@ const UserList = () => {
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<Link to="/edit/new" className="add-new-button" state={{ users }}>
|
||||||
<Link to="/edit/new" className="add-new-button">
|
Add New User
|
||||||
Add New User
|
</Link>
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue