From d908b2987cc4a21204386615aee4412ad93b30f5 Mon Sep 17 00:00:00 2001 From: Kakabay <2kakabayashyrberdyew@gmail.com> Date: Thu, 17 Oct 2024 18:31:55 +0500 Subject: [PATCH] websocket logic is changed --- components/vote/Countdown.tsx | 11 +- components/vote/ParticipantsList.tsx | 202 +++++++++++++-------------- 2 files changed, 105 insertions(+), 108 deletions(-) diff --git a/components/vote/Countdown.tsx b/components/vote/Countdown.tsx index c992c00..266a6e9 100644 --- a/components/vote/Countdown.tsx +++ b/components/vote/Countdown.tsx @@ -6,11 +6,18 @@ interface CountdownProps { startsAt: string; endsAt: string; setVoteStatus: Dispatch>; + setEventStatus: Dispatch>; + eventStatus: string; } -const Countdown: React.FC = ({ startsAt, endsAt, setVoteStatus }) => { +const Countdown: React.FC = ({ + startsAt, + endsAt, + setVoteStatus, + setEventStatus, + eventStatus, +}) => { const [timeLeft, setTimeLeft] = useState(''); - const [eventStatus, setEventStatus] = useState('Finished'); useEffect(() => { // Parsing the start and end times to Date objects in the correct format diff --git a/components/vote/ParticipantsList.tsx b/components/vote/ParticipantsList.tsx index defe4ca..e2c3550 100644 --- a/components/vote/ParticipantsList.tsx +++ b/components/vote/ParticipantsList.tsx @@ -1,18 +1,18 @@ -"use client"; -import React, { useContext, useEffect, useState } from "react"; -import GradientTitle from "./GradientTitle"; -import ParticipantCard from "./ParticipantCard"; -import { v4 } from "uuid"; -import { IAllVotes, VotingItem } from "@/models/allVotes.model"; -import { Queries } from "@/api/queries"; -import Loader from "../Loader"; -import VoteContext from "@/context/VoteContext"; -import PageBage from "./PageBage"; -import Image from "next/image"; -import { useMediaQuery } from "usehooks-ts"; -import Countdown from "./Countdown"; -import Link from "next/link"; -import { AnimatePresence } from "framer-motion"; +'use client'; +import React, { useContext, useEffect, useState } from 'react'; +import GradientTitle from './GradientTitle'; +import ParticipantCard from './ParticipantCard'; +import { v4 } from 'uuid'; +import { IAllVotes, VotingItem } from '@/models/allVotes.model'; +import { Queries } from '@/api/queries'; +import Loader from '../Loader'; +import VoteContext from '@/context/VoteContext'; +import PageBage from './PageBage'; +import Image from 'next/image'; +import { useMediaQuery } from 'usehooks-ts'; +import Countdown from './Countdown'; +import Link from 'next/link'; +import { AnimatePresence } from 'framer-motion'; interface IParams { vote_id?: string; @@ -30,6 +30,9 @@ const ParticipantsList = ({ vote_id }: IParams) => { const [data, setData] = useState(); const [participantsData, setParticipantsData] = useState([]); const [voteStatus, setVoteStatus] = useState(); + const [eventStatus, setEventStatus] = useState('Finished'); + const [manualClose, setManualClose] = useState(false); // Track manual closure + const [winnersCount, setWinnersCount] = useState(0); // States realted to web socket @@ -37,7 +40,7 @@ const ParticipantsList = ({ vote_id }: IParams) => { const [socket, setSocket] = useState(null); const [isConnected, setIsConnected] = useState(false); - const mobile = useMediaQuery("(max-width: 768px)"); + const mobile = useMediaQuery('(max-width: 768px)'); const { setVoteDescription } = useContext(VoteContext).voteDescriptionContext; @@ -72,68 +75,73 @@ const ParticipantsList = ({ vote_id }: IParams) => { const connectWebSocket = () => { try { - socket = new WebSocket( - `wss://sms.turkmentv.gov.tm/ws/voting?dst=${smsNumber}` - ); - setSocket(socket); + // Only connect if manualClose is false + if (!manualClose) { + socket = new WebSocket(`wss://sms.turkmentv.gov.tm/ws/voting?dst=${smsNumber}`); + setSocket(socket); - socket.onopen = () => { - console.log("WebSocket is connected"); - setIsConnected(true); - // addVotes(); + socket.onopen = () => { + console.log('WebSocket is connected'); + setIsConnected(true); - pingInterval = setInterval(() => { - if (socket?.readyState === WebSocket.OPEN) { - try { - socket.send(JSON.stringify({ type: "ping" })); - // addVotes(); - } catch (error) { - console.error("Error sending ping:", error); + pingInterval = setInterval(() => { + if (socket?.readyState === WebSocket.OPEN) { + try { + socket.send(JSON.stringify({ type: 'ping' })); + } catch (error) { + console.error('Error sending ping:', error); + } } + }, 25000); // Ping every 25 seconds + }; + + socket.onmessage = (event) => { + try { + const message = JSON.parse(event.data); + handleWebSocketMessage(message); + } catch (error) { + console.error('Error processing message:', error); } - }, 25000); // Ping every 25 seconds - }; + }; - socket.onmessage = (event) => { - try { - console.log("Message received from WebSocket:", event.data); - const message = JSON.parse(event.data); - handleWebSocketMessage(message); - } catch (error) { - console.error("Error processing message:", error); - } - }; + socket.onerror = (error) => { + console.error('WebSocket error:', error); - socket.onerror = (error) => { - console.error("WebSocket error:", error); - }; + if (!manualClose && !reconnectTimeout) { + reconnectTimeout = setTimeout(() => { + console.log('Attempting to reconnect WebSocket after error...'); + connectWebSocket(); + }, 5000); // Reconnect after 5 seconds + } + }; - socket.onclose = () => { - console.log("WebSocket is closed"); - setIsConnected(false); + socket.onclose = () => { + console.log('WebSocket is closed'); + setIsConnected(false); - if (pingInterval) { - clearInterval(pingInterval); - } + if (pingInterval) { + clearInterval(pingInterval); + } - if (!reconnectTimeout) { - reconnectTimeout = setTimeout(() => { - console.log("Attempting to reconnect WebSocket..."); - connectWebSocket(); - }, 5000); // Reconnect after 5 seconds - } - }; + // Clean up resources on close + if (reconnectTimeout) { + clearTimeout(reconnectTimeout); + } + }; + } } catch (error) { - console.error("WebSocket connection error:", error); + console.error('WebSocket connection error:', error); } }; - if (smsNumber) { + // WebSocket connection only if eventStatus is 'Started' + if (smsNumber && eventStatus === 'Started' && !manualClose) { connectWebSocket(); } return () => { if (socket) { + setManualClose(true); // Mark it as a manual close socket.close(); } if (reconnectTimeout) { @@ -143,7 +151,7 @@ const ParticipantsList = ({ vote_id }: IParams) => { clearInterval(pingInterval); } }; - }, [smsNumber]); + }, [smsNumber, eventStatus, manualClose]); // Add manualClose to dependencies const handleWebSocketMessage = (message: ISocketMessage) => { setParticipantsData((prevVotingItems) => { @@ -151,9 +159,7 @@ const ParticipantsList = ({ vote_id }: IParams) => { // Update the corresponding voting item const updatedItems = prevVotingItems.map((item, index) => - item.id === message.voting_item_id - ? { ...item, votes_count: item.votes_count + 1 } - : item + item.id === message.voting_item_id ? { ...item, votes_count: item.votes_count + 1 } : item, ); // Sort the updated items array by votes_count in descending order @@ -167,10 +173,10 @@ const ParticipantsList = ({ vote_id }: IParams) => { // Update the corresponding voting item const updatedItems = prevVotingItems.map((item, index) => - index === 1 ? { ...item, votes_count: item.votes_count + 1 } : item + index === 1 ? { ...item, votes_count: item.votes_count + 1 } : item, ); - console.log("votes updated"); + console.log('votes updated'); console.log(updatedItems.sort((a, b) => b.votes_count - a.votes_count)); // Sort the updated items array by votes_count in descending order return updatedItems.sort((a, b) => b.votes_count - a.votes_count); @@ -180,10 +186,7 @@ const ParticipantsList = ({ vote_id }: IParams) => { const winnersCountHandle = (winners: VotingItem[]) => { let count = 0; winners.map((winner) => { - if ( - winner.votes_percents === 100 && - winner.votes_count === winners[0].votes_count - ) { + if (winner.votes_percents === 100 && winner.votes_count === winners[0].votes_count) { count++; setWinnersCount(count); } @@ -197,27 +200,21 @@ const ParticipantsList = ({ vote_id }: IParams) => { if (!data?.data) { return (
- +
); } return (
- {data.data.description ? ( - - ) : null} + {data.data.description ? : null} {data.data.banner ? (
{mobile ? ( {data.data.title} { endsAt={data.data.ends_at} startsAt={data.data.starts_at} setVoteStatus={setVoteStatus} + setEventStatus={setEventStatus} + eventStatus={eventStatus} /> ) : null}
- {winnersCount > 1 ? ( - - ) : null} + {winnersCount > 1 ? : null} {participantsData && participantsData[0].votes_count > 0 ? (
{participantsData.map((participant, index) => - participant.votes_count === - participantsData[0].votes_count ? ( + participant.votes_count === participantsData[0].votes_count ? ( participant.url ? ( + key={v4()}> { key={v4()} index={index} hasUrl={false} - voteStatus={voteStatus ? voteStatus : ""} + voteStatus={voteStatus ? voteStatus : ''} isFirst={index === 0 ? true : false} name={participant.title} progress={participant.votes_percents} @@ -296,14 +291,12 @@ const ParticipantsList = ({ vote_id }: IParams) => { winner={true} /> ) - ) : null + ) : null, )}
) : null} - {winnersCount > 1 ? ( -
- ) : null} + {winnersCount > 1 ?
: null}
@@ -312,15 +305,14 @@ const ParticipantsList = ({ vote_id }: IParams) => { !hasVotes ? ( participant.url ? ( + key={v4()}> { hasUrl={false} key={v4()} index={index} - voteStatus={voteStatus ? voteStatus : ""} + voteStatus={voteStatus ? voteStatus : ''} isFirst={index === 0 ? true : false} name={participant.title} progress={participant.votes_percents} @@ -350,19 +342,17 @@ const ParticipantsList = ({ vote_id }: IParams) => { /> ) ) : ( - participant.votes_count !== - participantsData[0].votes_count && + participant.votes_count !== participantsData[0].votes_count && (participant.url ? ( + key={v4()}> { hasUrl={false} key={v4()} index={index} - voteStatus={voteStatus ? voteStatus : ""} + voteStatus={voteStatus ? voteStatus : ''} isFirst={index === 0 ? true : false} name={participant.title} progress={participant.votes_percents} @@ -391,7 +381,7 @@ const ParticipantsList = ({ vote_id }: IParams) => { winner={false} /> )) - ) + ), ) : null}