Added websocket

This commit is contained in:
Manik Maity
2024-11-13 18:37:05 +05:30
parent b3525c16dc
commit b394bbbd07
16 changed files with 308 additions and 48 deletions

View File

@@ -1,4 +1,5 @@
import React from "react";
import { Link } from "react-router-dom";
const ErrorFallback = ({ onRetry }) => {
return (
@@ -14,6 +15,9 @@ const ErrorFallback = ({ onRetry }) => {
>
Retry
</button>
<Link to="/" className="btn btn-ghost w-full">
Go Home
</Link>
</div>
</div>
);

View File

@@ -5,6 +5,7 @@ import { useQuery, useQueryClient } from "react-query";
import ErrorFallback from "../components/Errors/ErrorFallback";
import useBookmark from "../hooks/useBookmark";
import { useNavigate } from "react-router-dom";
import { formatDataByDate } from "../utils/util";
function Bookmark() {
const { handleBookmark } = useBookmark();
@@ -34,6 +35,7 @@ function Bookmark() {
});
await handleBookmark(bookmarkId);
};
console.log(data);
return (
<div className="p-6 bg-base-200 h-screen">
@@ -58,7 +60,7 @@ function Bookmark() {
</tr>
</thead>
<tbody>
{data?.data?.map((bookmark, index) => (
{formatDataByDate(data.data).map((bookmark, index) => (
<tr key={bookmark._id}>
<th>{index + 1}</th>
<td className="text-white text-sm md:text-base">

View File

@@ -4,12 +4,14 @@ import { FaPlus, FaTrashAlt } from "react-icons/fa";
import { useMutation } from "react-query";
import createPollService from "../services/createPollService";
import { toast } from "react-toastify";
import { useNavigate } from "react-router-dom";
function CreatePollForm() {
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
const [options, setOptions] = useState([]);
const [optionInput, setOptionInput] = useState("");
const navigate = useNavigate();
const handleAddOption = () => {
if (optionInput.trim() == "") {
@@ -31,6 +33,7 @@ function CreatePollForm() {
const message = data?.message || "Poll created successfully";
toast.success(message);
handleClearPoll();
navigate(`/view/${data?.data?._id}`);
},
onError: (error) => {
console.log(error);

View File

@@ -8,6 +8,7 @@ import useLogout from "../hooks/useLogout";
import { useQuery } from "react-query";
import getUserPollData from "../services/getUserPollData";
import ErrorFallback from "../components/Errors/ErrorFallback";
import { formatDataByDate } from "../utils/util";
function Dashboard() {
const navigator = useNavigate();
@@ -23,7 +24,6 @@ function Dashboard() {
}
);
console.log(data);
const pollData = [
{
@@ -108,7 +108,7 @@ function Dashboard() {
</thead>
<tbody>
{data.map((poll, index) => (
{formatDataByDate(data)?.map((poll, index) => (
<PollTableRow key={poll._id} refetch={refetch} poll={poll} index={index} /> // Replace with actual path
))}
</tbody>

View File

@@ -1,38 +1,59 @@
import React, { useState } from 'react'
import { useQuery } from 'react-query'
import getPollsService from '../services/getPollsService'
import PollCard from '../components/PollCard/PollCard'
import ErrorFallback from '../components/Errors/ErrorFallback'
import React, { useState } from "react";
import { useQuery } from "react-query";
import getPollsService from "../services/getPollsService";
import PollCard from "../components/PollCard/PollCard";
import ErrorFallback from "../components/Errors/ErrorFallback";
function Polls() {
const [page, setPage] = useState(1);
const [limit, setLimit] = useState(6);
const {data, isLoading, isError, isSuccess, refetch} = useQuery(["polls", page, limit], () => getPollsService(page, limit), {
cacheTime: 1000 * 60 * 5, // 5 minutes
staleTime: 1000 * 60 * 10, // 10 minutes
})
const { data, isLoading, isError, isSuccess, refetch } = useQuery(
["polls", page, limit],
() => getPollsService(page, limit),
{
cacheTime: 1000 * 60 * 5,
staleTime: 1000 * 60 * 10,
}
);
return (
<div className="container mx-auto p-4 bg-base-200">
<h1 className="text-2xl font-bold text-center mb-6">Polls</h1>
{isSuccess && <div className="flex flex-wrap justify-center gap-6">
{data?.data?.polls?.map((poll) => (
<PollCard key={poll._id} poll={poll} />
))}
</div>}
{isLoading && <div className='flex flex-wrap justify-center gap-6 skeleton min-h-40'></div>}
{isError && <div className='flex justify-center gap-6'>
<ErrorFallback onRetry={() => refetch()} />
</div>}
<h1 className="text-2xl font-bold text-center mb-6">Polls</h1>
{isSuccess && (
<div className="flex flex-wrap justify-center gap-6">
{data?.data?.polls?.map((poll) => (
<PollCard key={poll._id} poll={poll} />
))}
</div>
)}
{isLoading && (
<div className="flex flex-wrap justify-center gap-6 skeleton min-h-40"></div>
)}
{isError && (
<div className="flex justify-center gap-6">
<ErrorFallback onRetry={() => refetch()} />
</div>
)}
<div className='flex justify-center gap-6 mt-6'>
<button className='btn btn-primary btn-circle' disabled={page <= 1} onClick={() => setPage(page - 1)}>Prev</button>
<button className='btn btn-primary btn-circle' disabled={data?.data?.totalPages === page} onClick={() => setPage(page + 1)}>Next</button>
<div className="flex justify-center gap-6 mt-6">
<button
className="btn btn-primary btn-circle"
disabled={page <= 1}
onClick={() => setPage(page - 1)}
>
Prev
</button>
<button
className="btn btn-primary btn-circle"
disabled={data?.data?.totalPages === page}
onClick={() => setPage(page + 1)}
>
Next
</button>
</div>
</div>
</div>
)
);
}
export default Polls
export default Polls;

View File

@@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { Bar } from "react-chartjs-2";
import {
Chart as ChartJS,
@@ -15,30 +15,73 @@ import { FaBookmark } from "react-icons/fa";
import { toast } from "react-toastify";
import { makeChartDataObjFromPollData } from "../utils/util";
import useBookmark from "../hooks/useBookmark";
import { io } from "socket.io-client";
ChartJS.register(BarElement, CategoryScale, LinearScale);
function VotingPage() {
const { pollId } = useParams();
const [seletedOption, setSeletedOption] = useState(null);
const {handleBookmark} = useBookmark()
const [selectedOption, setSelectedOption] = useState(null);
const { handleBookmark } = useBookmark();
const [poll, setPoll] = useState(null);
const [socket, setSocket] = useState(null);
useEffect(() => {
const s = io("http://localhost:3000");
setSocket(s);
s.on("connect", () => {
console.log("Connected to the server");
s.emit("joinPoll", pollId);
});
return () => {
s.disconnect();
};
}, [pollId]);
const {
data: poll,
data,
isLoading,
isError,
refetch,
} = useQuery(["poll", pollId], () => getPollData(pollId), {
cacheTime: 10 * 100 * 60, // 10 minutes
staleTime: 20 * 100 * 60, // 20 minutes
cacheTime: 10 * 60 * 1000, // 10 minutes
staleTime: 20 * 60 * 1000, // 20 minutes
onSuccess: (data) => {
setPoll(data);
},
});
useEffect(() => {
if (socket) {
socket.on("pollDataUpdated", (data) => {
console.log("Received updated poll data:", data);
setPoll(data);
});
socket.on("error", (error) => {
console.error("Socket error:", error.message);
});
return () => {
socket.off("pollDataUpdated");
socket.off("error");
};
}
}, [socket]);
const mutation = useMutation(createVoteService, {
onSuccess: (data) => {
toast.success("Vote given successfully");
toast.success("Vote submitted successfully");
if (socket) {
socket.emit("vote", { pollId, success: data?.success });
}
},
onError: (error) => {
console.log(error);
console.error(error);
toast.error(
error?.response?.data?.message || "An unexpected error occurred"
);
@@ -46,6 +89,7 @@ function VotingPage() {
});
const handleOptionSelect = (id) => {
setSelectedOption(id);
mutation.mutate({ pollId, optionId: id });
};
@@ -61,6 +105,9 @@ function VotingPage() {
);
}
const chartData = makeChartDataObjFromPollData(poll);
return (
<div className="bg-base-200 min-h-screen p-6 text-white flex flex-col items-center">
<div className="w-full flex justify-between max-w-lg">
@@ -99,9 +146,9 @@ function VotingPage() {
onClick={() => handleOptionSelect(option._id)}
key={option._id}
className={`md:p-4 p-2 ${
seletedOption == option._id ? "bg-blue-500" : "bg-base-100"
selectedOption == option._id ? "bg-blue-500" : "bg-base-100"
} rounded-lg shadow-md flex items-center justify-center cursor-pointer ${
seletedOption == option._id ? "outline" : "hover:bg-base-300"
selectedOption == option._id ? "outline" : "hover:bg-base-300"
} transition`}
>
<span className="text-lg">{option.name}</span>

View File

@@ -19,4 +19,9 @@ export const makeChartDataObjFromPollData = (poll) => {
},
],
};
}
export const formatDataByDate = (data) => {
const fromatedData = data.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
return fromatedData;
}