diff --git a/client/src/containers/Admin/Users/AllUsers.css b/client/src/containers/Admin/Users/AllUsers.css new file mode 100644 index 0000000..0a2329a --- /dev/null +++ b/client/src/containers/Admin/Users/AllUsers.css @@ -0,0 +1,153 @@ +.users-wrapper { + padding: 20px; +} + +/* Header */ +.header-row { + display: flex; + justify-content: space-between; + align-items: center; +} + +/* Filters */ +.filters { + display: flex; + flex-wrap: wrap; + gap: 12px; + margin: 20px 0; +} + +.filters input, +.filters select { + padding: 8px; + border-radius: 6px; + border: 1px solid #ccc; +} + +/* Scrollable Table */ +.table-scroll { + width: 100%; + overflow-x: auto; +} + +.users-table { + width: 100%; + border-collapse: collapse; +} + +.users-table th, +.users-table td { + padding: 10px; + border: 1px solid #ddd; +} + +.wrap { + word-wrap: break-word; + max-width: 250px; +} + +/* Badges */ +.badge { + padding: 5px 8px; + border-radius: 6px; + font-weight: bold; + text-transform: capitalize; +} + +.badge.active { + background: #4caf50; + color: white; +} + +.badge.archived { + background: #b71c1c; + color: white; +} + +.badge.yes { + background: #007bff; + color: white; +} + +.badge.no { + background: #616161; + color: white; +} + +/* Archive Button */ +.archive-btn { + background: #d32f2f; + color: white; + border: none; + padding: 6px 10px; + border-radius: 6px; + cursor: pointer; +} + +.archive-btn:hover { + opacity: 0.85; +} + +/* Edit Button */ +.edit-btn { + background: #007bff; + color: white; + padding: 6px 10px; + border-radius: 6px; + text-decoration: none; +} + +.edit-btn:hover { + opacity: 0.85; +} + +/* Email clickable link */ +.email-link { + color: #007bff; + text-decoration: none; +} + +.email-link:hover { + text-decoration: underline; +} + +/* Pagination */ +.pagination { + display: flex; + justify-content: center; + margin-top: 20px; + gap: 15px; +} + +.pagination button { + padding: 8px 12px; + border: none; + background: #007bff; + color: white; + border-radius: 6px; + cursor: pointer; +} + +.pagination button:disabled { + opacity: 0.5; +} + +/* Home Link */ +.home-link { + display: block; + text-align: center; + margin-top: 25px; + color: #007bff; + text-decoration: none; +} + +/* MOBILE */ +@media (max-width: 600px) { + .filters { + flex-direction: column; + } + + .wrap { + max-width: 140px; + } +} diff --git a/client/src/containers/Admin/Users/AllUsers.tsx b/client/src/containers/Admin/Users/AllUsers.tsx index e0be1a8..7ea76d5 100644 --- a/client/src/containers/Admin/Users/AllUsers.tsx +++ b/client/src/containers/Admin/Users/AllUsers.tsx @@ -1,69 +1,260 @@ -import React, { useEffect, useState } from 'react' -// import { useParams } from "react-router-dom"; +// import React, { useEffect, useState } from 'react' +// // import { useParams } from "react-router-dom"; +// import axios from "axios"; +// import {Link} from 'react-router-dom' + +// const AllUsers = () => { +// const [data, setData] = useState([]); +// // const { id } = useParams(); + +// const getData = async () => { +// const { data } = await axios.get(`/api/user/view`); +// setData(data); +// }; + +// useEffect(() => { +// getData(); +// }, []); + + +// return ( +// <> +//
AllUsers
+ +//

I will create a login with authorization and authentication for Admin's and User's momentarily


+ +// Users API. This is Raw Data coming from the database. This will be used to apply all Users Information to the page for the admin edit user or freeze user or even archive."

+ +// {/* {JSON.stringify(data)}

*/} +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// {data.map((r: any, id: any) => ( +// +// +// +// +// +// +// +// +// +// {/* */} +// +// ))} +// +//
EditEmailPasswordDescriptionArchivedAdminDeveloper
+// {" "} +// {/* */} +// Edit {r.email ? r.email : "No Email"}{r.password ? r.password : "NoPassword"}{r.description ? r.description : "No Information"}{r.archived ? r.archived : "Active"}{r.admin ? r.admin : "No"}{r.developer? r.developer : "No"}{r}
+// {/* Click to edit single user, change information, approve business to use the site + credit, or archive user.

*/} + +//
+// Home +// +// ) +// } + +// export default AllUsers + +import React, { useEffect, useState } from "react"; +import { Link, useNavigate } from "react-router-dom"; import axios from "axios"; -import {Link} from 'react-router-dom' +import "./AllUsers.css"; -const AllUsers = () => { - const [data, setData] = useState([]); - // const { id } = useParams(); +interface User { + _id: string; + email: string; + password?: string; + description?: string; + archived?: boolean; + admin?: boolean; + developer?: boolean; +} + +const ITEMS_PER_PAGE = 10; + +const AllUsers: React.FC = () => { + const [users, setUsers] = useState([]); + const [search, setSearch] = useState(""); + const [archivedFilter, setArchivedFilter] = useState("all"); + const [page, setPage] = useState(1); + const navigate = useNavigate(); - const getData = async () => { - const { data } = await axios.get(`/api/user/view`); - setData(data); + // Fetch users + const fetchUsers = async () => { + try { + const { data } = await axios.get("/api/user/view"); + setUsers(data); + } catch (error) { + console.error("Error fetching users:", error); + } }; useEffect(() => { - getData(); + fetchUsers(); }, []); + // Filtered users + const filteredUsers = users.filter((user) => { + const matchesSearch = + user.email?.toLowerCase().includes(search.toLowerCase()) || + user.description?.toLowerCase().includes(search.toLowerCase()); + const matchesArchived = + archivedFilter === "all" || + (archivedFilter === "archived" && user.archived) || + (archivedFilter === "active" && !user.archived); + return matchesSearch && matchesArchived; + }); + + // Pagination + const startIndex = (page - 1) * ITEMS_PER_PAGE; + const pageUsers = filteredUsers.slice( + startIndex, + startIndex + ITEMS_PER_PAGE + ); + const totalPages = Math.ceil(filteredUsers.length / ITEMS_PER_PAGE); + + // Archive toggle + const toggleArchive = async (id: string, current: boolean) => { + try { + await axios.put(`/api/user/archive/${id}`, { archived: !current }); + setUsers((prev) => + prev.map((u) => (u._id === id ? { ...u, archived: !current } : u)) + ); + } catch (error) { + console.error("Error updating archive:", error); + } + }; return ( - <> -
AllUsers
- -

I will create a login with authorization and authentication for Admin's and User's momentarily


- - Users API. This is Raw Data coming from the database. This will be used to apply all Users Information to the page for the admin edit user or freeze user or even archive."

- - {/* {JSON.stringify(data)}

*/} - - - - - - - - - - - - - - - {data.map((r: any, id: any) => ( - - - - - - - - - - {/* */} +
+
+

All Users

+
+ + {/* Search + Filter */} +
+ setSearch(e.target.value)} + /> + +
+ + {/* Scrollable table */} +
+
EditEmailPasswordDescriptionArchivedAdminDeveloper
- {" "} - {/* */} - Edit {r.email ? r.email : "No Email"}{r.password ? r.password : "NoPassword"}{r.description ? r.description : "No Information"}{r.archived ? r.archived : "Active"}{r.admin ? r.admin : "No"}{r.developer? r.developer : "No"}{r}
+ + + + + + + + + - ))} - -
Email (click to edit)PasswordDescriptionArchivedAdminDeveloperActions
- {/* Click to edit single user, change information, approve business to use the site + credit, or archive user.

*/} - -
- Home - - ) -} + + + {pageUsers.length > 0 ? ( + pageUsers.map((user) => ( + + + + {user.email} + + + {user.password || "—"} + {user.description || "—"} + + + {user.archived ? "Archived" : "Active"} + + + + + {user.admin ? "Yes" : "No"} + + + + + {user.developer ? "Yes" : "No"} + + + + +   + + Edit + + + + )) + ) : ( + + + No users found + + + )} + + + + + {/* Pagination */} + {totalPages > 1 && ( +
+ + + Page {page} of {totalPages} + + +
+ )} + + + Back Home + + + ); +}; -export default AllUsers \ No newline at end of file +export default AllUsers; diff --git a/client/src/containers/Admin/Users/UserProfile/UserProfile.tsx b/client/src/containers/Admin/Users/UserProfile/UserProfile.tsx index d64cd2a..8c1dc57 100644 --- a/client/src/containers/Admin/Users/UserProfile/UserProfile.tsx +++ b/client/src/containers/Admin/Users/UserProfile/UserProfile.tsx @@ -1,229 +1,346 @@ -import React from "react"; -import Button from "react-bootstrap/Button" -import { Link } from "react-router-dom"; +// import React from "react"; +// import Button from "react-bootstrap/Button" +// import { Link } from "react-router-dom"; + +// const UserProfile = () => { +// return ( +// <> +//
+//
+//
+// Profile Update +//
+ +//
+//
+//
+// +// +//
+// +// +// +// We'll never share your email with anyone else. +// +//
+//
+// +// +//
+//
+// +// +//
+//
+//
+// +// +//
+//
+// +// +//
+//
+//
+// +// +//
+//
+// +// +//
+//
+//
+// +// +//
+//
+// +// +//
+//
+// +// +//
+//
+//
+//
+// +// +//
+//
+//
+// +// +//
+//
+// +// +//
+//
+// +// +//
+//
+// +// +//
+//
+// +// +//
+//
+// +// +//
+//
+// +// +//
+//
+// +// +//
+//
+// +// +//
+// +//
+//
+//
+// Home +// +// ); +// }; + +// export default UserProfile; + +import React, { useEffect, useState } from "react"; +import { useParams, useNavigate, Link } from "react-router-dom"; +import axios from "axios"; +import Button from "react-bootstrap/Button"; + +interface User { + email: string; + password?: string; + description?: string; +} + +const UserProfile: React.FC = () => { + const { id } = useParams<{ id: string }>(); + const navigate = useNavigate(); + const [user, setUser] = useState({ email: "", password: "", description: "" }); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [success, setSuccess] = useState(false); + + // Fetch user by ID + const fetchUser = async () => { + try { + const { data } = await axios.get(`/api/user/${id}`); + setUser(data); + } catch (err) { + setError("Failed to fetch user."); + console.error(err); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + fetchUser(); + }, [id]); + + // Handle input changes + const handleChange = (e: React.ChangeEvent) => { + const { name, value } = e.target; + setUser((prev) => ({ ...prev, [name]: value })); + }; + + // Handle form submit + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + try { + await axios.put(`/api/user/update/${id}`, { + email: user.email, + password: user.password, + description: user.description, + }); + setSuccess(true); + setTimeout(() => navigate("/AllUsers"), 1000); + } catch (err) { + setError("Failed to update user."); + console.error(err); + } + }; + + if (loading) return

Loading user data...

; -const UserProfile = () => { return ( - <> -
-
-
- Profile Update -
- -
-
-
- - -
- - - - We'll never share your email with anyone else. - -
-
- - -
-
- - -
-
-
- - -
-
- - -
-
-
- - -
-
- - -
-
-
- - -
-
- - -
-
- - -
-
-
-
- - -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
- -
+
+

Update User

+ {error &&

{error}

} + {success &&

User updated successfully!

} + +
+
+ + +
+ +
+ +
-
- Home - + +
+ +