Added get all created poll in frontend ✔️
This commit is contained in:
@@ -59,7 +59,44 @@ pollRouter.get("/test", (req, res) => {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
pollRouter.post("/create", validator(pollDataSchema), verifyToken, createPollController);
|
pollRouter.post("/create", validator(pollDataSchema), verifyToken, createPollController);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /poll/data/{pollId}:
|
||||||
|
* get:
|
||||||
|
* summary: Get poll data
|
||||||
|
* tags: [Poll]
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: pollId
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* required: true
|
||||||
|
* description: Poll ID
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Poll data fetched successfully
|
||||||
|
* 401:
|
||||||
|
* description: Unauthorized
|
||||||
|
* 500:
|
||||||
|
* description: Internal server error
|
||||||
|
*/
|
||||||
pollRouter.get("/data/:pollId", verifyToken, getPollDataController);
|
pollRouter.get("/data/:pollId", verifyToken, getPollDataController);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /poll/created:
|
||||||
|
* get:
|
||||||
|
* summary: Get all created polls
|
||||||
|
* tags: [Poll]
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: All created polls fetched successfully
|
||||||
|
* 401:
|
||||||
|
* description: Unauthorized
|
||||||
|
* 500:
|
||||||
|
* description: Internal server error
|
||||||
|
*/
|
||||||
pollRouter.get("/created", verifyToken, getAllCreatedPollsController);
|
pollRouter.get("/created", verifyToken, getAllCreatedPollsController);
|
||||||
|
|
||||||
export default pollRouter;
|
export default pollRouter;
|
||||||
22
frontend/src/components/Errors/ErrorFallback.jsx
Normal file
22
frontend/src/components/Errors/ErrorFallback.jsx
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const ErrorFallback = ({ onRetry }) => {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center justify-center min-h-full w-full bg-base-200 p-4">
|
||||||
|
<div className="card w-full max-w-md bg-base-100 shadow-xl text-center space-y-4 p-6">
|
||||||
|
<h2 className="text-xl font-bold text-error">Oops! Something went wrong</h2>
|
||||||
|
<p className="text-sm text-base-content">
|
||||||
|
We encountered an unexpected error. Please try again.
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
className="btn btn-primary w-full"
|
||||||
|
onClick={() => onRetry()}
|
||||||
|
>
|
||||||
|
Retry
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ErrorFallback;
|
||||||
@@ -2,13 +2,12 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { FaTrashAlt, FaUserEdit } from "react-icons/fa";
|
import { FaTrashAlt, FaUserEdit } from "react-icons/fa";
|
||||||
|
|
||||||
function PollTableRow({ poll, index }) {
|
function PollTableRow({ poll, index, refetch }) {
|
||||||
const [showEditForm, setShowEditForm] = useState(false);
|
const [showEditForm, setShowEditForm] = useState(false);
|
||||||
|
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
const sure = window.confirm("Are you sure you want to delete this poll?");
|
const sure = window.confirm("Are you sure you want to delete this poll?");
|
||||||
if (sure) {
|
if (sure) {
|
||||||
// Call the delete poll function here
|
|
||||||
console.log(`Poll with ID: ${poll._id} has been deleted.`);
|
console.log(`Poll with ID: ${poll._id} has been deleted.`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -26,7 +25,6 @@ function PollTableRow({ poll, index }) {
|
|||||||
<td className="text-gray-400 whitespace-normal break-words max-w-xs">
|
<td className="text-gray-400 whitespace-normal break-words max-w-xs">
|
||||||
{poll.description}
|
{poll.description}
|
||||||
</td>
|
</td>
|
||||||
<td className="text-white">{poll.totalVotes}</td>
|
|
||||||
<td>
|
<td>
|
||||||
{poll.published ? (
|
{poll.published ? (
|
||||||
<span className="badge badge-success text-white">Published</span>
|
<span className="badge badge-success text-white">Published</span>
|
||||||
@@ -36,9 +34,6 @@ function PollTableRow({ poll, index }) {
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div className="flex md:flex-row flex-col gap-2 flex-nowrap">
|
<div className="flex md:flex-row flex-col gap-2 flex-nowrap">
|
||||||
<button onClick={() => setShowEditForm(true)} className="btn btn-sm btn-info flex items-center">
|
|
||||||
<FaUserEdit className="mr-1" /> Edit
|
|
||||||
</button>
|
|
||||||
<button onClick={handleDelete} className="btn btn-sm btn-error flex items-center">
|
<button onClick={handleDelete} className="btn btn-sm btn-error flex items-center">
|
||||||
<FaTrashAlt className="mr-1" /> Delete
|
<FaTrashAlt className="mr-1" /> Delete
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -5,51 +5,96 @@ import PollTableRow from "../components/PollTableRow/PollTableRow";
|
|||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import useUserStore from "../store/useStore";
|
import useUserStore from "../store/useStore";
|
||||||
import useLogout from "../hooks/useLogout";
|
import useLogout from "../hooks/useLogout";
|
||||||
|
import { useQuery } from "react-query";
|
||||||
|
import getUserPollData from "../services/getUserPollData";
|
||||||
|
import ErrorFallback from "../components/Errors/ErrorFallback";
|
||||||
|
|
||||||
function Dashboard() {
|
function Dashboard() {
|
||||||
|
|
||||||
const navigator = useNavigate();
|
const navigator = useNavigate();
|
||||||
const { handleLogout } = useLogout();
|
const { handleLogout } = useLogout();
|
||||||
|
const { user } = useUserStore();
|
||||||
|
|
||||||
|
const { data, isLoading, isError, refetch, isSuccess } = useQuery(
|
||||||
|
["polls", user._id],
|
||||||
|
getUserPollData,
|
||||||
|
{
|
||||||
|
cacheTime: 1000 * 60 * 5, // 5 minutes
|
||||||
|
staleTime: 1000 * 60 * 10, // 10 minutes
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
const pollData = [
|
const pollData = [
|
||||||
{ _id: "1", title: "Poll 1", description: "Description of Poll 1", totalVotes: 120, published: true },
|
{
|
||||||
{ _id: "2", title: "Poll 2", description: "Description of Poll 2", totalVotes: 45, published: false },
|
_id: "1",
|
||||||
|
title: "Poll 1",
|
||||||
|
description: "Description of Poll 1",
|
||||||
|
totalVotes: 120,
|
||||||
|
published: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_id: "2",
|
||||||
|
title: "Poll 2",
|
||||||
|
description: "Description of Poll 2",
|
||||||
|
totalVotes: 45,
|
||||||
|
published: false,
|
||||||
|
},
|
||||||
// Add more poll data as needed
|
// Add more poll data as needed
|
||||||
];
|
];
|
||||||
|
|
||||||
const {user} = useUserStore();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col lg:flex-row min-h-screen bg-base-200">
|
<div className="flex flex-col lg:flex-row min-h-screen bg-base-200">
|
||||||
{/* User Profile Sidebar */}
|
{/* User Profile Sidebar */}
|
||||||
<aside className="w-min lg:w-1/4 bg-slate-800 rounded-md m-4 bg-opacity-50 shadow-lg p-4 flex flex-col items-center">
|
<aside className="w-min lg:w-1/4 bg-slate-800 rounded-md m-4 bg-opacity-50 shadow-lg p-4 flex flex-col items-center">
|
||||||
<img
|
<img
|
||||||
src={`https://placehold.co/200x200?text=${user?.username[0] || "LivePoll"}`} // Replace with actual path
|
src={`https://placehold.co/200x200?text=${
|
||||||
|
user?.username[0] || "LivePoll"
|
||||||
|
}`} // Replace with actual path
|
||||||
alt="User Profile"
|
alt="User Profile"
|
||||||
className="rounded-full h-24 w-24 object-cover mb-4"
|
className="rounded-full h-24 w-24 object-cover mb-4"
|
||||||
/>
|
/>
|
||||||
<h2 className="text-2xl font-bold text-center text-white">{user?.username || "User"}</h2>
|
<h2 className="text-2xl font-bold text-center text-white">
|
||||||
<p className="mt-2 text-center text-gray-400">{user?.email || "Email"}</p>
|
{user?.username || "User"}
|
||||||
|
</h2>
|
||||||
|
<p className="mt-2 text-center text-gray-400">
|
||||||
|
{user?.email || "Email"}
|
||||||
|
</p>
|
||||||
<button className="btn btn-primary mt-4 w-full">Edit Profile</button>
|
<button className="btn btn-primary mt-4 w-full">Edit Profile</button>
|
||||||
<button className="btn btn-error btn-outline mt-4 w-full" onClick={handleLogout}>Logout</button>
|
<button
|
||||||
|
className="btn btn-error btn-outline mt-4 w-full"
|
||||||
|
onClick={handleLogout}
|
||||||
|
>
|
||||||
|
Logout
|
||||||
|
</button>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
{/* Dashboard Main Content */}
|
{/* Dashboard Main Content */}
|
||||||
<main className="w-full lg:w-3/4 p-6">
|
<main className="w-full lg:w-3/4 p-6">
|
||||||
{/* Dashboard Header */}
|
{/* Dashboard Header */}
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h1 className="text-2xl md:text-4xl font-bold text-white">Poll Dashboard</h1>
|
<h1 className="text-2xl md:text-4xl font-bold text-white">
|
||||||
<p className="md:text-lg text-gray-300">Manage your polls, view results, and edit as needed.</p>
|
Poll Dashboard
|
||||||
|
</h1>
|
||||||
|
<p className="md:text-lg text-gray-300">
|
||||||
|
Manage your polls, view results, and edit as needed.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Add New Poll Button */}
|
{/* Add New Poll Button */}
|
||||||
<div className="flex justify-end mb-4">
|
<div className="flex justify-end mb-4">
|
||||||
<button className="btn btn-primary" onClick={() => navigator("/create")}>
|
<button
|
||||||
|
className="btn btn-primary"
|
||||||
|
onClick={() => navigator("/create")}
|
||||||
|
>
|
||||||
Add New Poll <FaPlus />
|
Add New Poll <FaPlus />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Polls Table */}
|
{/* Polls Table */}
|
||||||
|
{isError && <div className="h-60 w-full"><ErrorFallback onRetry={refetch}/></div>}
|
||||||
|
{isLoading && <div className="skeleton h-40 w-full"></div>}
|
||||||
|
{isSuccess &&
|
||||||
<div className="overflow-x-auto">
|
<div className="overflow-x-auto">
|
||||||
<table className="table w-full bg-gray-800 text-white">
|
<table className="table w-full bg-gray-800 text-white">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -57,18 +102,19 @@ function Dashboard() {
|
|||||||
<th>#</th>
|
<th>#</th>
|
||||||
<th>Title</th>
|
<th>Title</th>
|
||||||
<th>Description</th>
|
<th>Description</th>
|
||||||
<th>Total Votes</th>
|
|
||||||
<th>Published</th>
|
<th>Published</th>
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{pollData.map((poll, index) => (
|
{data.map((poll, index) => (
|
||||||
<PollTableRow key={poll._id} poll={poll} index={index} /> // Replace with actual path
|
<PollTableRow key={poll._id} refetch={refetch} poll={poll} index={index} /> // Replace with actual path
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
8
frontend/src/services/getUserPollData.js
Normal file
8
frontend/src/services/getUserPollData.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import axiosInstance from "../helper/axiosInstance"
|
||||||
|
|
||||||
|
async function getUserPollData() {
|
||||||
|
const responses = await axiosInstance.get("/poll/created");
|
||||||
|
return responses.data.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getUserPollData
|
||||||
Reference in New Issue
Block a user