Skip to content

Commit

Permalink
Merge pull request #388 from MeetDOD/issue-338
Browse files Browse the repository at this point in the history
Feat: Created manage user by admin block/unblock users based on their activity successfully Issue 338
  • Loading branch information
Ultimateutkarsh11 authored Jul 8, 2024
2 parents ad76c8f + 8748af8 commit b929b52
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 171 deletions.
292 changes: 123 additions & 169 deletions admin/src/pages/Users.tsx
Original file line number Diff line number Diff line change
@@ -1,184 +1,138 @@
import { useState } from "react";
import Navbar from "../components/Navbar"
import { useState, useEffect } from "react";
import axios from "axios";
import Navbar from "../components/Navbar";
import SideBar from "../components/SideBar";
import { useRecoilValue } from "recoil";
import { tokenState } from "../store/atoms/auth";
import toast from "react-hot-toast";

export interface IUser {
id: string;
username: string;
email: string;
verified: boolean;
blocked: boolean;
createdAt: string;
comments:[];
posts: [];
following: [];
}

const Users = () => {
const [sidebarOpen, setSidebarOpen] = useState(false);
const [allUsers, setAllUsers] = useState<IUser[]>([]);
const token = useRecoilValue(tokenState);

const toggleSidebar = () => {
setSidebarOpen(!sidebarOpen);
};

useEffect(() => {
const fetchUsers = async () => {
try {
const response = await axios.get("/api/v1/admin/allUsers", {
headers: {
Authorization: `Bearer ${token}`,
},
});
setAllUsers(response.data.allUsers.reverse());
} catch (error) {
console.error("Error fetching users:", error);
}
};

fetchUsers();
}, [token]);

const handleBlock = async (userId: string) => {
try {
const response = await axios.patch(
`/api/v1/admin/block/${userId}`,
{},
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
toast.success(response.data.message);
setAllUsers(allUsers.map(user => user.id === userId ? { ...user, blocked: true } : user));
} catch (error) {
console.error("Error blocking user:", error);
toast.error("Error blocking user");
}
};

const handleUnblock = async (userId: string) => {
try {
const response = await axios.patch(
`/api/v1/admin/unblock/${userId}`,
{},
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
toast.success(response.data.message);
setAllUsers(allUsers.map(user => user.id === userId ? { ...user, blocked: false } : user));
} catch (error) {
console.error("Error unblocking user:", error);
toast.error("Error unblocking user");
}
};

return (
<div>
<Navbar toggleSidebar={toggleSidebar} />
<Navbar toggleSidebar={toggleSidebar} />
<div className="flex-1 flex flex-col lg:ml-80">
<SideBar sidebarOpen={sidebarOpen} toggleSidebar={toggleSidebar} />
<div className="mx-5 lg:mr-11 overflow-x-auto shadow-md rounded-xl mb-5">
<table className="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
<thead className="text-xs text-white uppercase bg-sky-500">
<tr>
<th scope="col" className="px-6 py-3">
Name
</th>
<th scope="col" className="px-6 py-3">
Posts
</th>
<th scope="col" className="px-6 py-3">
followers
</th>
<th scope="col" className="px-6 py-3">
Action
</th>
</tr>
</thead>
<tbody>
<tr className="border-b bg-[#000435] border-sky-500 hover:bg-blue-950 hover:text-white">
<th className="flex items-center px-6 py-5 text-white">
<img className="h-10 w-10 rounded-full" src={`https://ui-avatars.com/api/?name=meet&background=0ea5e9&color=fff&rounded=true&bold=true`} alt="profile-pic" />
<div className="ps-3">
<div className="text-base font-bold">Neil Sims</div>
<div className="font-medium text-gray-300 ">[email protected]</div>
</div>
</th>
<td className="px-8 py-4 font-semibold">
10
</td>
<td className="px-12 py-4 font-semibold">
7
</td>
<td className="px-2 py-4 ">
<button className='font-semibold rounded-md p-2 bg-sky-500 text-white px-4 hover:bg-sky-600'>
Manage
</button>
</td>
</tr>
<tr className="border-b bg-[#000435] border-sky-500 hover:bg-blue-950 hover:text-white">
<th className="flex items-center px-6 py-5 text-white">
<img className="h-10 w-10 rounded-full" src={`https://ui-avatars.com/api/?name=meet&background=0ea5e9&color=fff&rounded=true&bold=true`} alt="profile-pic" />
<div className="ps-3">
<div className="text-base font-bold">Neil Sims</div>
<div className="font-medium text-gray-300 ">[email protected]</div>
</div>
</th>
<td className="px-8 py-4 font-semibold">
10
</td>
<td className="px-12 py-4 font-semibold">
7
</td>
<td className="px-2 py-4 ">
<button className='font-semibold rounded-md p-2 bg-sky-500 text-white px-4 hover:bg-sky-600'>
Manage
</button>
</td>
</tr>
<tr className="border-b bg-[#000435] border-sky-500 hover:bg-blue-950 hover:text-white">
<th className="flex items-center px-6 py-5 text-white">
<img className="h-10 w-10 rounded-full" src={`https://ui-avatars.com/api/?name=meet&background=0ea5e9&color=fff&rounded=true&bold=true`} alt="profile-pic" />
<div className="ps-3">
<div className="text-base font-bold">Neil Sims</div>
<div className="font-medium text-gray-300 ">[email protected]</div>
</div>
</th>
<td className="px-8 py-4 font-semibold">
10
</td>
<td className="px-12 py-4 font-semibold">
7
</td>
<td className="px-2 py-4 ">
<button className='font-semibold rounded-md p-2 bg-sky-500 text-white px-4 hover:bg-sky-600'>
Manage
</button>
</td>
</tr>
<tr className="border-b bg-[#000435] border-sky-500 hover:bg-blue-950 hover:text-white">
<th className="flex items-center px-6 py-5 text-white">
<img className="h-10 w-10 rounded-full" src={`https://ui-avatars.com/api/?name=meet&background=0ea5e9&color=fff&rounded=true&bold=true`} alt="profile-pic" />
<div className="ps-3">
<div className="text-base font-bold">Neil Sims</div>
<div className="font-medium text-gray-300 ">[email protected]</div>
</div>
</th>
<td className="px-8 py-4 font-semibold">
10
</td>
<td className="px-12 py-4 font-semibold">
7
</td>
<td className="px-2 py-4 ">
<button className='font-semibold rounded-md p-2 bg-sky-500 text-white px-4 hover:bg-sky-600'>
Manage
</button>
</td>
</tr>
<tr className="border-b bg-[#000435] border-sky-500 hover:bg-blue-950 hover:text-white">
<th className="flex items-center px-6 py-5 text-white">
<img className="h-10 w-10 rounded-full" src={`https://ui-avatars.com/api/?name=meet&background=0ea5e9&color=fff&rounded=true&bold=true`} alt="profile-pic" />
<div className="ps-3">
<div className="text-base font-bold">Neil Sims</div>
<div className="font-medium text-gray-300 ">[email protected]</div>
</div>
</th>
<td className="px-8 py-4 font-semibold">
10
</td>
<td className="px-12 py-4 font-semibold">
7
</td>
<td className="px-2 py-4 ">
<button className='font-semibold rounded-md p-2 bg-sky-500 text-white px-4 hover:bg-sky-600'>
Manage
</button>
</td>
</tr>
<tr className="border-b bg-[#000435] border-sky-500 hover:bg-blue-950 hover:text-white">
<th className="flex items-center px-6 py-5 text-white">
<img className="h-10 w-10 rounded-full" src={`https://ui-avatars.com/api/?name=meet&background=0ea5e9&color=fff&rounded=true&bold=true`} alt="profile-pic" />
<div className="ps-3">
<div className="text-base font-bold">Neil Sims</div>
<div className="font-medium text-gray-300 ">[email protected]</div>
</div>
</th>
<td className="px-8 py-4 font-semibold">
10
</td>
<td className="px-12 py-4 font-semibold">
7
</td>
<td className="px-2 py-4 ">
<button className='font-semibold rounded-md p-2 bg-sky-500 text-white px-4 hover:bg-sky-600'>
Manage
</button>
</td>
</tr>
<tr className="border-b bg-[#000435] border-sky-500 hover:bg-blue-950 hover:text-white">
<th className="flex items-center px-6 py-5 text-white">
<img className="h-10 w-10 rounded-full" src={`https://ui-avatars.com/api/?name=meet&background=0ea5e9&color=fff&rounded=true&bold=true`} alt="profile-pic" />
<div className="ps-3">
<div className="text-base font-bold">Neil Sims</div>
<div className="font-medium text-gray-300 ">[email protected]</div>
</div>
</th>
<td className="px-8 py-4 font-semibold">
10
</td>
<td className="px-12 py-4 font-semibold">
7
</td>
<td className="px-2 py-4 ">
<button className='font-semibold rounded-md p-2 bg-sky-500 text-white px-4 hover:bg-sky-600'>
Manage
</button>
</td>
</tr>
</tbody>
</table>
</div>
<SideBar sidebarOpen={sidebarOpen} toggleSidebar={toggleSidebar} />
<div className="mx-5 lg:mr-11 overflow-x-auto shadow-md rounded-xl mb-5">
<table className="w-full rtl:text-right text-gray-500 dark:text-gray-400">
<thead className="text-xs md:text-sm text-white uppercase bg-sky-500 text-center">
<tr>
<th scope="col" className="px-6 py-3">Photo</th>
<th scope="col" className="px-8 py-3 text-start">Name</th>
<th scope="col" className="px-6 py-3">signup At</th>
<th scope="col" className="px-6 py-3">Posts</th>
<th scope="col" className="px-6 py-3">Followers</th>
<th scope="col" className="px-6 py-3">Comments</th>
<th scope="col" className="px-6 py-3">Action</th>
</tr>
</thead>
<tbody>
{allUsers.map(user => (
<tr key={user.id} className="text-xs md:text-sm text-center border-b bg-[#000435] border-sky-500 hover:bg-blue-950 hover:text-white">
<td className="pl-7"><img className="h-10 w-10 rounded-full" src={`https://ui-avatars.com/api/?name=${user.username}&background=0ea5e9&color=fff&rounded=true&bold=true`} alt="profile-pic" /></td>
<td className="px-8 py-4 font-semibold">
<div className="flex flex-col items-start">
<span className="font-bold">{user.username}</span>
<span className="font-thin text-gray-300">{user.email}</span>
</div>
</td>
<td className="px-8 py-4 font-semibold">{new Date(user.createdAt).toLocaleDateString()}</td>
<td className="px-8 py-4 font-semibold">{user.posts.length}</td>
<td className="px-12 py-4 font-semibold">{user.following.length}</td>
<td className="px-8 py-4 font-semibold">{user.comments.length}</td>
<td className="px-2 py-4">
{user.blocked ? (
<button onClick={() => handleUnblock(user.id)} className="font-semibold rounded-md p-2 bg-red-500 text-white border-2 px-4 hover:bg-red-600">
Unblock
</button>
) : (
<button onClick={() => handleBlock(user.id)} className="font-semibold rounded-md p-2 bg-sky-500 text-white px-6 border-2 hover:bg-sky-600">
Block
</button>
)}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
)
}
);
};

export default Users
export default Users;
1 change: 1 addition & 0 deletions backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ model User {
email String
passwordHash String
verified Boolean @default(false)
blocked Boolean @default(false)
otp Int?
isAdmin Boolean @default(false)
posts Post[] @relation("authorPosts")
Expand Down
72 changes: 71 additions & 1 deletion backend/src/routes/admin/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,74 @@ export const adminProfileController = async (req: UserAuthRequest, res: Response
res.status(200).json({
user,
});
};
};

export const blockUserController = async (req: Request, res: Response) => {
const { userId } = req.params;

try {
const user = await prisma.user.update({
where: { id: userId },
data: { blocked: true },
});

res.status(200).json({
message: `User ${user.username} has been blocked.`,
});
} catch (error) {
res.status(500).json({
error: "An unexpected exception occurred!",
});
}
};

export const unblockUserController = async (req: Request, res: Response) => {
const { userId } = req.params;

try {
const user = await prisma.user.update({
where: { id: userId },
data: { blocked: false },
});

res.status(200).json({
message: `User ${user.username} has been unblocked.`,
});
} catch (error) {
res.status(500).json({
error: "An unexpected exception occurred!",
});
}
};

export const allUserForAdmin = async (req: Request, res:Response) => {
try{
const allUsers = await prisma.user.findMany({
where: {
isAdmin:false
},
select: {
id:true,
username:true,
email:true,
blocked:true,
posts:true,
createdAt:true,
comments:true,
following: {
select: {
id: true
}
}
},
});
res.status(200).json({
message: "Successfully fetched All Users!",
allUsers,
});
}catch(error){
res.status(500).json({
error: "An unexpected exception occurred!",
});
}
}
Loading

0 comments on commit b929b52

Please sign in to comment.