Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/MeetDOD/StyleShare into iss…
Browse files Browse the repository at this point in the history
…ue-555
  • Loading branch information
MeetDOD committed Aug 3, 2024
2 parents 1fe4e48 + 8ca1686 commit d60445e
Show file tree
Hide file tree
Showing 26 changed files with 232 additions and 23 deletions.
2 changes: 2 additions & 0 deletions admin/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import Comments from "./pages/Comments";
import Layout from "./components/Layout";
import Favorites from "./pages/Favorites";
import Reactions from "./pages/Reactions";
import UsersFeedbacks from "./pages/UsersFeedbacks";
// import axios from "axios";
// axios.defaults.baseURL = "http://localhost:3001/";

Expand All @@ -43,6 +44,7 @@ function App() {
<Route path="" element={<Dashboard />} />
<Route path="profile" element={<Profile />} />
<Route path="users" element={<Users />} />
<Route path="userfeedbacks" element={<UsersFeedbacks />} />
<Route path="posts" element={<Posts />} />
<Route path="update-post/:postId" element={<UpdatePost />} />
<Route path="statistics" element={<Graphs />} />
Expand Down
Binary file added admin/src/assets/avatars/avatar1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added admin/src/assets/avatars/avatar2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added admin/src/assets/avatars/avatar3.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added admin/src/assets/avatars/avatar4.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added admin/src/assets/avatars/avatar5.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions admin/src/components/SideBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { FaRegComments } from "react-icons/fa";
import GoogleTranslate from './GoogleTranslate';
import { RiHeartsLine } from "react-icons/ri";
import { VscReactions } from "react-icons/vsc";
import { VscFeedback } from "react-icons/vsc";

const SideBar = ({ sidebarOpen, toggleSidebar }: { sidebarOpen: boolean, toggleSidebar: () => void }) => {
const location = useLocation();
Expand Down Expand Up @@ -39,6 +40,7 @@ const SideBar = ({ sidebarOpen, toggleSidebar }: { sidebarOpen: boolean, toggleS
<Link to="/admin/comments" className={linkClasses('/admin/comments')}><FaRegComments size={23} className='mr-3'/>Comments</Link>
<Link to="/admin/favorites" className={linkClasses('/admin/favorites')}><RiHeartsLine size={23} className='mr-3'/>Favorites</Link>
<Link to="/admin/reactions" className={linkClasses('/admin/reactions')}><VscReactions size={23} className='mr-3'/>Reactions</Link>
<Link to="/admin/userfeedbacks" className={linkClasses('/admin/userfeedbacks')}><VscFeedback size={23} className='mr-3'/>Feedbacks</Link>
<Link to="/admin/statistics" className={linkClasses('/admin/statistics')}><VscGraphScatter size={23} className='mr-3'/>Statistics</Link>
</nav>
</div>
Expand Down
2 changes: 1 addition & 1 deletion admin/src/pages/Comments.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ const Comments = () => {
<td colSpan={4} className="px-8 py-4">
<div className="flex items-start space-x-4">
<div className="flex-shrink-0">
<img className="h-10 w-10 rounded-full" src={`https://ui-avatars.com/api/?name=${comment.user.username}&background=0ea5e9&color=fff&rounded=true&bold=true`} alt="profile-pic" />
<img className="h-10 w-10 rounded-full" src={comment.user?.avatar?.replace('/app', '/admin') || `https://ui-avatars.com/api/?name=${comment.user?.username}&background=0ea5e9&color=fff&rounded=true&bold=true`} alt="profile-pic" />
</div>
<div className="min-w-0 flex-1">
<p className="text-sm font-medium text-white">
Expand Down
2 changes: 1 addition & 1 deletion admin/src/pages/Favorites.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const Favorites = () => {
{favoritePosts.map(favorite => (
<tr key={favorite.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=${favorite.user.username}&background=0ea5e9&color=fff&rounded=true&bold=true`} alt="profile-pic" />
<img className="h-10 w-10 rounded-full" src={favorite.user?.avatar?.replace('/app', '/admin') || `https://ui-avatars.com/api/?name=${favorite.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">
Expand Down
2 changes: 1 addition & 1 deletion admin/src/pages/Reactions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const Reactions = () => {
{reactions.map(reaction => (
<tr key={reaction.user.id + reaction.post.id + reaction.type} 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=${reaction.user?.username}&background=0ea5e9&color=fff&rounded=true&bold=true`} alt="profile-pic" />
<img className="h-10 w-10 rounded-full" src={reaction.user?.avatar?.replace('/app', '/admin') || `https://ui-avatars.com/api/?name=${reaction.user?.username}&background=0ea5e9&color=fff&rounded=true&bold=true`} alt="profile-pic" />
</td>
<td className="px-6 py-4 font-semibold">
<div className="flex flex-col items-start">
Expand Down
3 changes: 2 additions & 1 deletion admin/src/pages/Users.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const Users = () => {
});
setAllUsers(response.data.allUsers.reverse());
setLoading(false);
console.log(response.data.allUsers)
} catch (error) {
console.error("Error fetching users:", error);
setLoading(true);
Expand Down Expand Up @@ -131,7 +132,7 @@ const Users = () => {
<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="pl-7"><img className="h-10 w-10 rounded-full" src={user?.avatar?.replace('/app', '/admin') || `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>
Expand Down
117 changes: 117 additions & 0 deletions admin/src/pages/UsersFeedbacks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { useState, useEffect } from "react";
import axios from "axios";
import { useRecoilValue } from "recoil";
import { tokenState } from "../store/atoms/auth";
import { IFeedback } from "../types";
import { ColorRing } from 'react-loader-spinner';
import { VscFeedback } from "react-icons/vsc";
import toast from "react-hot-toast";

const GetFeedbacks = () => {
const [feedbacks, setFeedbacks] = useState<IFeedback[]>([]);
const [loading, setLoading] = useState(true);
const token = useRecoilValue(tokenState);

document.title = "Style Share Admin | Manage Feedbacks 💬"

useEffect(() => {
const fetchFeedbacks = async () => {
try {
const response = await axios.get("/api/v1/admin/getfeedback", {
headers: {
Authorization: `Bearer ${token}`,
},
});
setFeedbacks(response.data);
setLoading(false);
} catch (error) {
console.error("Error fetching feedbacks:", error);
setLoading(true);
}
};

fetchFeedbacks();
}, [token]);

const handleToggleVisibility = async (feedbackId: string) => {
try {
await axios.patch(
`/api/v1/admin/toggleFeedbackVisibility/${feedbackId}`,
{},
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
toast.success("Feedback visibility updated");
setFeedbacks(feedbacks.map(feedback =>
feedback.id === feedbackId ? { ...feedback, visible: !feedback.visible } : feedback
));
} catch (error) {
console.error("Error updating feedback visibility:", error);
toast.error("Error updating feedback visibility");
}
};

return (
<div>
<div className="flex-1 flex flex-col lg:ml-80">
<div className="mx-5 mb-5">
<span className="flex items-center text-xl font-bold decoration-sky-500 decoration-dotted underline">
<div className='inline-block p-2 text-white bg-[#000435] rounded-lg mr-2'>
<VscFeedback size={23} />
</div>
All Feedbacks
</span>
</div>
{loading ?
<div className="flex justify-center items-center h-80">
<ColorRing
visible={true}
height="100"
width="100"
colors={['#000435', 'rgb(14 165 233)', 'rgb(243 244 246)', '#000435', 'rgb(14 165 233)']}
/>
</div>
:
<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">User</th>
<th scope="col" className="px-8 py-3">Comment</th>
<th scope="col" className="px-6 py-3">Rating</th>
<th scope="col" className="px-6 py-3">Created At</th>
<th scope="col" className="px-16 py-3">Action</th>
</tr>
</thead>
<tbody>
{feedbacks.map(feedback => (
<tr key={feedback.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="px-8">
<span className="font-bold">{feedback.user.username}</span>
</td>
<td className="px-8 py-4 font-semibold">{feedback.comment}</td>
<td className="px-8 py-4 font-semibold">{feedback.rating}</td>
<td className="px-8 py-4 font-semibold">{new Date(feedback.createdAt).toLocaleDateString()}</td>
<td className="px-2 py-4 grid justify-center text-center">
<button
className={`font-semibold rounded-md p-2 text-white border-2 ${feedback.visible ? 'bg-red-500 hover:bg-red-600' : 'bg-sky-500 hover:bg-sky-600'}`}
onClick={() => handleToggleVisibility(feedback.id)}
>
{feedback.visible ? 'Hide from Testimonials' : 'Show on Testimonials'}
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
}
</div>
</div>
);
};

export default GetFeedbacks;
12 changes: 11 additions & 1 deletion admin/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export interface IFavoritePost {
id: string;
username: string;
email: string;
avatar?:string;
};
post: {
id: string;
Expand All @@ -80,4 +81,13 @@ export interface IReaction {
createdAt: number;
user: IUser;
post: IPost;
}
}

export interface IFeedback {
id: string;
comment: string;
rating: number;
createdAt: string;
user: IUser;
visible: boolean;
}
1 change: 1 addition & 0 deletions backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ model Feedback {
rating Int
comment String
userId String @db.ObjectId
visible Boolean @default(false)
user User @relation("userFeedbacks", fields: [userId], references: [id])
createdAt DateTime @default(now())
}
Expand Down
50 changes: 49 additions & 1 deletion backend/src/routes/admin/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ export const allUserForAdmin = async (req: Request, res:Response) => {
posts:true,
createdAt:true,
comments:true,
avatar:true,
following: {
select: {
id: true
Expand Down Expand Up @@ -167,6 +168,7 @@ export const getAdminPostsController = async (req: Request, res: Response) => {
select: {
username: true,
email: true,
avatar:true
},
},
},
Expand Down Expand Up @@ -486,6 +488,7 @@ export const getPostReactionsController = async (req: Request, res: Response) =>
id: true,
username: true,
email: true,
avatar:true
},
},
post: {
Expand Down Expand Up @@ -527,7 +530,8 @@ export const getFavoritesController = async (req: Request, res: Response) => {
select: {
id: true,
username: true,
email: true
email: true,
avatar:true
}
},
post: {
Expand Down Expand Up @@ -642,6 +646,50 @@ export const downloadReportController = async (req: UserAuthRequest, res: Respon
}
};

export const getFeedbacks = async (req: Request, res: Response) => {
try {
const feedbacks = await prisma.feedback.findMany({
include: {
user: {
select: {
id: true,
username: true,
avatar: true,
},
},
},
});

res.status(200).json(feedbacks);
} catch (error) {
console.error('Error fetching feedbacks:', error);
res.status(500).json({ error: 'An unexpected error occurred!' });
}
};

export const toggleFeedbackVisibility = async (req: Request, res: Response) => {
const { id } = req.params;
try {
const feedback = await prisma.feedback.findUnique({
where: { id },
});

if (!feedback) {
return res.status(404).json({ error: 'Feedback not found' });
}

const updatedFeedback = await prisma.feedback.update({
where: { id },
data: { visible: !feedback.visible },
});

res.status(200).json(updatedFeedback);
} catch (error) {
console.error('Error toggling feedback visibility:', error);
res.status(500).json({ error: 'An unexpected error occurred!' });
}
};

export const downloadUsersReportController = async (req: Request, res: Response) => {
try {
const currentDate = new Date().toLocaleDateString();
Expand Down
6 changes: 5 additions & 1 deletion backend/src/routes/admin/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Router} from 'express';
import { getPostReactionsController,getFavoritesController,adminLoginController, adminProfileController, allUserForAdmin, blockUserController, unblockUserController, getAdminPostsController, getAdminTrendingPostsController, getAdminStatsController, getGraphsStatsController, updatePostController, deletePostController, getPostByIdController, getAllContactMessages, deleteCommentController, downloadReportController, downloadUsersReportController, downloadContactMessagesReportController, downloadPostsReportController } from './controller';
import { getPostReactionsController,getFavoritesController,adminLoginController, adminProfileController, allUserForAdmin, blockUserController, unblockUserController, getAdminPostsController, getAdminTrendingPostsController, getAdminStatsController, getGraphsStatsController, updatePostController, deletePostController, getPostByIdController, getAllContactMessages, deleteCommentController, downloadReportController, getFeedbacks, toggleFeedbackVisibility, downloadUsersReportController, downloadContactMessagesReportController, downloadPostsReportController } from './controller';
import { isAdmin } from '../../middleware/adminAuth';

const adminRouter = Router();
Expand Down Expand Up @@ -44,4 +44,8 @@ adminRouter.get('/downloadpostsreport',isAdmin, downloadPostsReportController);

adminRouter.get('/downloadcontactmessagereport',isAdmin, downloadContactMessagesReportController);

adminRouter.get('/getfeedback',isAdmin, getFeedbacks);

adminRouter.patch('/toggleFeedbackVisibility/:id', isAdmin, toggleFeedbackVisibility);

export default adminRouter;
3 changes: 3 additions & 0 deletions backend/src/routes/user/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,9 @@ export const createFeedback = async (req: UserAuthRequest, res: Response) => {
export const getFeedbacks = async (req: Request, res: Response) => {
try {
const feedbacks = await prisma.feedback.findMany({
where:{
visible:true
},
include: {
user: {
select: {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/FAQ.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ const FAQ: React.FC = () => {
backgroundPosition: "center",
}}
>
<h2 className="text-2xl md:text-[37px] mb-14 font-bold text-white transition-shadow duration-300 hover:shadow-[1px_1px_5px_rgb(0,255,208),_0_0_1em_rgb(238,71,224),_0_0_0.2em_rgb(255,0,200)]">
<h2 className="text-2xl md:text-[37px] mb-14 font-bold text-[#000435] dark:text-white">
Frequently Asked Questions!
</h2>
<dl className="flex flex-col items-center">
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/components/Features.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,28 @@ const Features = () => {
<div className="flex flex-wrap -m-4">
<div className="xl:w-1/4 md:w-1/2 p-4">
<div className="border border-sky-500 border-opacity-75 p-6 rounded-lg hover:bg-blue-300 dark:hover:bg-blue-950 hover:border-sky-700 backdrop-blur-sm cursor-pointer transition-transform duration-300 hover:-translate-y-1">
<img src={responsiveDesignGif} alt="Responsive Design" className="w-full mb-4" />
<img src={responsiveDesignGif} alt="Responsive Design" className="w-full mb-4 transition-transform duration-300 ease-in-out hover:scale-[1.02]" loading="lazy" />
<h2 className="text-lg text-[#000435] dark:text-white font-medium title-font mb-2">Responsive Design</h2>
<p className="leading-relaxed text-base">All components are from best sources and designed to be fully responsive 📝 ensuring they look great on any device📱</p>
</div>
</div>
<div className="xl:w-1/4 md:w-1/2 p-4">
<div className="border border-sky-500 border-opacity-75 p-6 rounded-lg hover:bg-blue-300 dark:hover:bg-blue-950 hover:border-sky-700 backdrop-blur-sm cursor-pointer transition-transform duration-300 hover:-translate-y-1">
<img src={leaderboardGif} alt="Leaderboard" className="w-full mb-4" />
<img src={leaderboardGif} alt="Leaderboard" className="w-full mb-4 transition-transform duration-300 ease-in-out hover:scale-[1.02]" loading="lazy" />
<h2 className="text-lg text-[#000435] dark:text-white font-medium title-font mb-2">Leaderboard</h2>
<p className="leading-relaxed text-base">Compete with other developers and 🪜 climb the leaderboard by sharing your best components and get recognized 🥇</p>
</div>
</div>
<div className="xl:w-1/4 md:w-1/2 p-4">
<div className="border border-sky-500 border-opacity-75 p-6 rounded-lg hover:bg-blue-300 dark:hover:bg-blue-950 hover:border-sky-700 backdrop-blur-sm cursor-pointer transition-transform duration-300 hover:-translate-y-1">
<img src={personalizationGif} alt="Personalization" className="w-full mb-4" />
<img src={personalizationGif} alt="Personalization" className="w-full mb-4 transition-transform duration-300 ease-in-out hover:scale-[1.02]" loading="lazy" />
<h2 className="text-lg text-[#000435] dark:text-white font-medium title-font mb-2">Personalization</h2>
<p className="leading-relaxed text-base">Engage with the community by 👍/👎 components. Save your 💖 components for quick access in your future projects.</p>
</div>
</div>
<div className="xl:w-1/4 md:w-1/2 p-4">
<div className="border border-sky-500 border-opacity-75 p-6 rounded-lg hover:bg-blue-300 dark:hover:bg-blue-950 hover:border-sky-700 backdrop-blur-sm cursor-pointer transition-transform duration-300 hover:-translate-y-1">
<img src={customizableCodeSnippetsGif} alt="Customizable Code Snippets" className="w-full mb-4" />
<img src={customizableCodeSnippetsGif} alt="Customizable Code Snippets" className="w-full mb-4 transition-transform duration-300 ease-in-out hover:scale-[1.02]" loading="lazy" />
<h2 className="text-lg text-[#000435] dark:text-white font-medium title-font mb-2">Customizable Code Snippets</h2>
<p className="leading-relaxed text-base">Easily customize and preview code 👀 snippets with our built-in editor and A.I tailored specifically for Tailwind CSS 💅</p>
</div>
Expand Down
Loading

0 comments on commit d60445e

Please sign in to comment.