From 894cf5a2df954243ed701f556ffdc3d271ab1c92 Mon Sep 17 00:00:00 2001 From: Prabhat Yadav <133522303+Prabhatyadav60@users.noreply.github.com> Date: Fri, 5 Jul 2024 12:14:07 +0530 Subject: [PATCH 1/5] Update Footer.tsx --- frontend/src/components/Footer.tsx | 75 ++++++++++++++++++------------ 1 file changed, 45 insertions(+), 30 deletions(-) diff --git a/frontend/src/components/Footer.tsx b/frontend/src/components/Footer.tsx index 5fc3b72a..ae9e7aa5 100644 --- a/frontend/src/components/Footer.tsx +++ b/frontend/src/components/Footer.tsx @@ -3,7 +3,7 @@ import { Link } from "react-router-dom"; import { loggedInState } from '../store/atoms/auth'; import { CgProfile } from 'react-icons/cg'; import { BsFilePost } from 'react-icons/bs'; -import { FaHome,FaRegCopyright,FaGithub } from 'react-icons/fa'; +import { FaHome, FaRegCopyright, FaGithub, FaEnvelope, FaInfoCircle, FaTools } from 'react-icons/fa'; import { useTranslation } from 'react-i18next'; import logo from "../assets/favicon.png"; @@ -18,14 +18,14 @@ const Footer = () => {
- - Styleshare Logo - - {t('footer.heading')} - - + + Styleshare Logo + + {t('footer.heading')} + +
-

+

{t('A simple web-based platform where users can easily contribute, create, explore, share components.')}

@@ -35,13 +35,22 @@ const Footer = () => {

{t('footer.company')}

@@ -49,15 +58,15 @@ const Footer = () => {

{t('footer.quick')}

@@ -66,31 +75,37 @@ const Footer = () => {

{t('footer.legal')}

-
-
- - - - - - -
-
-
+
+
+ + + + + + +
+
+
{t('footer.copy1')} {currentYear} {t('footer.copy2')} -
+
) } From 4e40c48ab0eeb0454078dacfad3e16c8689804e0 Mon Sep 17 00:00:00 2001 From: Prabhat Yadav <133522303+Prabhatyadav60@users.noreply.github.com> Date: Fri, 5 Jul 2024 15:09:31 +0530 Subject: [PATCH 2/5] added favicons in "legal section" --- frontend/src/components/Footer.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/Footer.tsx b/frontend/src/components/Footer.tsx index ae9e7aa5..129e588b 100644 --- a/frontend/src/components/Footer.tsx +++ b/frontend/src/components/Footer.tsx @@ -3,7 +3,7 @@ import { Link } from "react-router-dom"; import { loggedInState } from '../store/atoms/auth'; import { CgProfile } from 'react-icons/cg'; import { BsFilePost } from 'react-icons/bs'; -import { FaHome, FaRegCopyright, FaGithub, FaEnvelope, FaInfoCircle, FaTools } from 'react-icons/fa'; +import { FaHome, FaRegCopyright, FaGithub, FaEnvelope, FaInfoCircle, FaTools, FaLock, FaFileAlt, FaCookieBite } from 'react-icons/fa'; import { useTranslation } from 'react-i18next'; import logo from "../assets/favicon.png"; @@ -75,17 +75,20 @@ const Footer = () => {

{t('footer.legal')}

diff --git a/frontend/src/pages/Contributors.tsx b/frontend/src/pages/Contributors.tsx new file mode 100644 index 00000000..0863a674 --- /dev/null +++ b/frontend/src/pages/Contributors.tsx @@ -0,0 +1,61 @@ +import React, { useEffect, useState } from 'react'; +import axios from 'axios'; +interface Contributor { + id: number; + login: string; + html_url: string; + avatar_url: string; + contributions: number; +} +const Contributors: React.FC = () => { + const [contributors, setContributors] = useState([]); + useEffect(() => { + async function fetchContributors() { + try { + const response = await axios.get( + 'https://api.github.com/repos/VaibhavArora314/StyleShare/contributors' + ); + setContributors(response.data); + } catch (error) { + console.error('Error fetching contributors:', error); + } + } + fetchContributors(); + }, []); + + return ( +
+
+

Contributors

+
+ {contributors.map((contributor) => ( +
+ + {contributor.login} + +

{contributor.login}

+ +

+ Contributions: {contributor.contributions} +

+
+ ))} +
+
+
+ ); +}; +export default Contributors; + From 0313aec6f1ae0743eae94f592c7ff1c1581cb732 Mon Sep 17 00:00:00 2001 From: pani2004 Date: Sat, 6 Jul 2024 12:51:09 +0530 Subject: [PATCH 4/5] Made it theme responsive --- frontend/src/pages/Contributors.tsx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/frontend/src/pages/Contributors.tsx b/frontend/src/pages/Contributors.tsx index 0863a674..c5fa88e4 100644 --- a/frontend/src/pages/Contributors.tsx +++ b/frontend/src/pages/Contributors.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useState } from 'react'; import axios from 'axios'; + interface Contributor { id: number; login: string; @@ -7,8 +8,10 @@ interface Contributor { avatar_url: string; contributions: number; } + const Contributors: React.FC = () => { const [contributors, setContributors] = useState([]); + useEffect(() => { async function fetchContributors() { try { @@ -24,14 +27,14 @@ const Contributors: React.FC = () => { }, []); return ( -
+

Contributors

{contributors.map((contributor) => (
{ className="w-24 h-24 rounded-full object-cover mb-4" /> -

{contributor.login}

- -

+

+ {contributor.login} +

+

Contributions: {contributor.contributions}

@@ -57,5 +61,6 @@ const Contributors: React.FC = () => {
); }; + export default Contributors; From 8748af8850dca53e2ee907cd41ae8d17edeef27e Mon Sep 17 00:00:00 2001 From: meet Date: Sun, 7 Jul 2024 23:25:00 +0530 Subject: [PATCH 5/5] Created block/unblock user for admin --- admin/src/pages/Users.tsx | 292 +++++++++++-------------- backend/prisma/schema.prisma | 1 + backend/src/routes/admin/controller.ts | 72 +++++- backend/src/routes/admin/route.ts | 8 +- 4 files changed, 202 insertions(+), 171 deletions(-) diff --git a/admin/src/pages/Users.tsx b/admin/src/pages/Users.tsx index 34ae33a3..94f5e1a6 100644 --- a/admin/src/pages/Users.tsx +++ b/admin/src/pages/Users.tsx @@ -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([]); + 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 (
- +
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Name - - Posts - - followers - - Action -
- profile-pic -
-
Neil Sims
-
neil.sims@flowbite.com
-
-
- 10 - - 7 - - -
- profile-pic -
-
Neil Sims
-
neil.sims@flowbite.com
-
-
- 10 - - 7 - - -
- profile-pic -
-
Neil Sims
-
neil.sims@flowbite.com
-
-
- 10 - - 7 - - -
- profile-pic -
-
Neil Sims
-
neil.sims@flowbite.com
-
-
- 10 - - 7 - - -
- profile-pic -
-
Neil Sims
-
neil.sims@flowbite.com
-
-
- 10 - - 7 - - -
- profile-pic -
-
Neil Sims
-
neil.sims@flowbite.com
-
-
- 10 - - 7 - - -
- profile-pic -
-
Neil Sims
-
neil.sims@flowbite.com
-
-
- 10 - - 7 - - -
-
+ +
+ + + + + + + + + + + + + + {allUsers.map(user => ( + + + + + + + + + + ))} + +
PhotoNamesignup AtPostsFollowersCommentsAction
profile-pic +
+ {user.username} + {user.email} +
+
{new Date(user.createdAt).toLocaleDateString()}{user.posts.length}{user.following.length}{user.comments.length} + {user.blocked ? ( + + ) : ( + + )} +
+
- ) -} + ); +}; -export default Users +export default Users; diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma index 1f114466..baa0228c 100644 --- a/backend/prisma/schema.prisma +++ b/backend/prisma/schema.prisma @@ -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") diff --git a/backend/src/routes/admin/controller.ts b/backend/src/routes/admin/controller.ts index 7a0b7322..496e6fe7 100644 --- a/backend/src/routes/admin/controller.ts +++ b/backend/src/routes/admin/controller.ts @@ -75,4 +75,74 @@ export const adminProfileController = async (req: UserAuthRequest, res: Response res.status(200).json({ user, }); -}; \ No newline at end of file +}; + +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!", + }); + } +} \ No newline at end of file diff --git a/backend/src/routes/admin/route.ts b/backend/src/routes/admin/route.ts index 123a94d7..4fb10648 100644 --- a/backend/src/routes/admin/route.ts +++ b/backend/src/routes/admin/route.ts @@ -1,5 +1,5 @@ import {Router} from 'express'; -import { adminLoginController, adminProfileController } from './controller'; +import { adminLoginController, adminProfileController, allUserForAdmin, blockUserController, unblockUserController } from './controller'; import { isAdmin } from '../../middleware/adminAuth'; const adminRouter = Router(); @@ -8,4 +8,10 @@ adminRouter.post("/login", adminLoginController); adminRouter.get("/me", isAdmin,adminProfileController ); +adminRouter.patch('/block/:userId', isAdmin, blockUserController); + +adminRouter.patch('/unblock/:userId', isAdmin, unblockUserController); + +adminRouter.get('/allUsers',isAdmin,allUserForAdmin); + export default adminRouter; \ No newline at end of file