websocket logic is changed

This commit is contained in:
Kakabay 2024-10-17 18:31:55 +05:00
parent 378183bfb8
commit d908b2987c
2 changed files with 105 additions and 108 deletions

View File

@ -6,11 +6,18 @@ interface CountdownProps {
startsAt: string; startsAt: string;
endsAt: string; endsAt: string;
setVoteStatus: Dispatch<SetStateAction<string | undefined>>; setVoteStatus: Dispatch<SetStateAction<string | undefined>>;
setEventStatus: Dispatch<SetStateAction<string>>;
eventStatus: string;
} }
const Countdown: React.FC<CountdownProps> = ({ startsAt, endsAt, setVoteStatus }) => { const Countdown: React.FC<CountdownProps> = ({
startsAt,
endsAt,
setVoteStatus,
setEventStatus,
eventStatus,
}) => {
const [timeLeft, setTimeLeft] = useState<string>(''); const [timeLeft, setTimeLeft] = useState<string>('');
const [eventStatus, setEventStatus] = useState<string>('Finished');
useEffect(() => { useEffect(() => {
// Parsing the start and end times to Date objects in the correct format // Parsing the start and end times to Date objects in the correct format

View File

@ -1,18 +1,18 @@
"use client"; 'use client';
import React, { useContext, useEffect, useState } from "react"; import React, { useContext, useEffect, useState } from 'react';
import GradientTitle from "./GradientTitle"; import GradientTitle from './GradientTitle';
import ParticipantCard from "./ParticipantCard"; import ParticipantCard from './ParticipantCard';
import { v4 } from "uuid"; import { v4 } from 'uuid';
import { IAllVotes, VotingItem } from "@/models/allVotes.model"; import { IAllVotes, VotingItem } from '@/models/allVotes.model';
import { Queries } from "@/api/queries"; import { Queries } from '@/api/queries';
import Loader from "../Loader"; import Loader from '../Loader';
import VoteContext from "@/context/VoteContext"; import VoteContext from '@/context/VoteContext';
import PageBage from "./PageBage"; import PageBage from './PageBage';
import Image from "next/image"; import Image from 'next/image';
import { useMediaQuery } from "usehooks-ts"; import { useMediaQuery } from 'usehooks-ts';
import Countdown from "./Countdown"; import Countdown from './Countdown';
import Link from "next/link"; import Link from 'next/link';
import { AnimatePresence } from "framer-motion"; import { AnimatePresence } from 'framer-motion';
interface IParams { interface IParams {
vote_id?: string; vote_id?: string;
@ -30,6 +30,9 @@ const ParticipantsList = ({ vote_id }: IParams) => {
const [data, setData] = useState<IAllVotes>(); const [data, setData] = useState<IAllVotes>();
const [participantsData, setParticipantsData] = useState<VotingItem[]>([]); const [participantsData, setParticipantsData] = useState<VotingItem[]>([]);
const [voteStatus, setVoteStatus] = useState<string>(); const [voteStatus, setVoteStatus] = useState<string>();
const [eventStatus, setEventStatus] = useState<string>('Finished');
const [manualClose, setManualClose] = useState(false); // Track manual closure
const [winnersCount, setWinnersCount] = useState<number>(0); const [winnersCount, setWinnersCount] = useState<number>(0);
// States realted to web socket // States realted to web socket
@ -37,7 +40,7 @@ const ParticipantsList = ({ vote_id }: IParams) => {
const [socket, setSocket] = useState<WebSocket | null>(null); const [socket, setSocket] = useState<WebSocket | null>(null);
const [isConnected, setIsConnected] = useState(false); const [isConnected, setIsConnected] = useState(false);
const mobile = useMediaQuery("(max-width: 768px)"); const mobile = useMediaQuery('(max-width: 768px)');
const { setVoteDescription } = useContext(VoteContext).voteDescriptionContext; const { setVoteDescription } = useContext(VoteContext).voteDescriptionContext;
@ -72,68 +75,73 @@ const ParticipantsList = ({ vote_id }: IParams) => {
const connectWebSocket = () => { const connectWebSocket = () => {
try { try {
socket = new WebSocket( // Only connect if manualClose is false
`wss://sms.turkmentv.gov.tm/ws/voting?dst=${smsNumber}` if (!manualClose) {
); socket = new WebSocket(`wss://sms.turkmentv.gov.tm/ws/voting?dst=${smsNumber}`);
setSocket(socket); setSocket(socket);
socket.onopen = () => { socket.onopen = () => {
console.log("WebSocket is connected"); console.log('WebSocket is connected');
setIsConnected(true); setIsConnected(true);
// addVotes();
pingInterval = setInterval(() => { pingInterval = setInterval(() => {
if (socket?.readyState === WebSocket.OPEN) { if (socket?.readyState === WebSocket.OPEN) {
try { try {
socket.send(JSON.stringify({ type: "ping" })); socket.send(JSON.stringify({ type: 'ping' }));
// addVotes(); } catch (error) {
} catch (error) { console.error('Error sending ping:', 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) => { socket.onerror = (error) => {
try { console.error('WebSocket error:', error);
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) => { if (!manualClose && !reconnectTimeout) {
console.error("WebSocket error:", error); reconnectTimeout = setTimeout(() => {
}; console.log('Attempting to reconnect WebSocket after error...');
connectWebSocket();
}, 5000); // Reconnect after 5 seconds
}
};
socket.onclose = () => { socket.onclose = () => {
console.log("WebSocket is closed"); console.log('WebSocket is closed');
setIsConnected(false); setIsConnected(false);
if (pingInterval) { if (pingInterval) {
clearInterval(pingInterval); clearInterval(pingInterval);
} }
if (!reconnectTimeout) { // Clean up resources on close
reconnectTimeout = setTimeout(() => { if (reconnectTimeout) {
console.log("Attempting to reconnect WebSocket..."); clearTimeout(reconnectTimeout);
connectWebSocket(); }
}, 5000); // Reconnect after 5 seconds };
} }
};
} catch (error) { } 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(); connectWebSocket();
} }
return () => { return () => {
if (socket) { if (socket) {
setManualClose(true); // Mark it as a manual close
socket.close(); socket.close();
} }
if (reconnectTimeout) { if (reconnectTimeout) {
@ -143,7 +151,7 @@ const ParticipantsList = ({ vote_id }: IParams) => {
clearInterval(pingInterval); clearInterval(pingInterval);
} }
}; };
}, [smsNumber]); }, [smsNumber, eventStatus, manualClose]); // Add manualClose to dependencies
const handleWebSocketMessage = (message: ISocketMessage) => { const handleWebSocketMessage = (message: ISocketMessage) => {
setParticipantsData((prevVotingItems) => { setParticipantsData((prevVotingItems) => {
@ -151,9 +159,7 @@ const ParticipantsList = ({ vote_id }: IParams) => {
// Update the corresponding voting item // Update the corresponding voting item
const updatedItems = prevVotingItems.map((item, index) => const updatedItems = prevVotingItems.map((item, index) =>
item.id === message.voting_item_id item.id === message.voting_item_id ? { ...item, votes_count: item.votes_count + 1 } : item,
? { ...item, votes_count: item.votes_count + 1 }
: item
); );
// Sort the updated items array by votes_count in descending order // 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 // Update the corresponding voting item
const updatedItems = prevVotingItems.map((item, index) => 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)); console.log(updatedItems.sort((a, b) => b.votes_count - a.votes_count));
// Sort the updated items array by votes_count in descending order // Sort the updated items array by votes_count in descending order
return updatedItems.sort((a, b) => b.votes_count - a.votes_count); return updatedItems.sort((a, b) => b.votes_count - a.votes_count);
@ -180,10 +186,7 @@ const ParticipantsList = ({ vote_id }: IParams) => {
const winnersCountHandle = (winners: VotingItem[]) => { const winnersCountHandle = (winners: VotingItem[]) => {
let count = 0; let count = 0;
winners.map((winner) => { winners.map((winner) => {
if ( if (winner.votes_percents === 100 && winner.votes_count === winners[0].votes_count) {
winner.votes_percents === 100 &&
winner.votes_count === winners[0].votes_count
) {
count++; count++;
setWinnersCount(count); setWinnersCount(count);
} }
@ -197,27 +200,21 @@ const ParticipantsList = ({ vote_id }: IParams) => {
if (!data?.data) { if (!data?.data) {
return ( return (
<div className="py-12"> <div className="py-12">
<GradientTitle title={"No voting to show on the site"} size="big" /> <GradientTitle title={'No voting to show on the site'} size="big" />
</div> </div>
); );
} }
return ( return (
<div className="flex flex-col gap-[20px] sm:gap-[40px] w-full items-center"> <div className="flex flex-col gap-[20px] sm:gap-[40px] w-full items-center">
{data.data.description ? ( {data.data.description ? <PageBage title={data.data.description} /> : null}
<PageBage title={data.data.description} />
) : null}
{data.data.banner ? ( {data.data.banner ? (
<div className="relative w-full md:min-h-[150px] md:h-auto h-[100px] "> <div className="relative w-full md:min-h-[150px] md:h-auto h-[100px] ">
{mobile ? ( {mobile ? (
<Image <Image
fill fill
src={ src={data.data.banner_mobile !== null ? data.data.banner_mobile : data.data.banner}
data.data.banner_mobile !== null
? data.data.banner_mobile
: data.data.banner
}
alt={data.data.title} alt={data.data.title}
unselectable="off" unselectable="off"
unoptimized unoptimized
@ -244,30 +241,28 @@ const ParticipantsList = ({ vote_id }: IParams) => {
endsAt={data.data.ends_at} endsAt={data.data.ends_at}
startsAt={data.data.starts_at} startsAt={data.data.starts_at}
setVoteStatus={setVoteStatus} setVoteStatus={setVoteStatus}
setEventStatus={setEventStatus}
eventStatus={eventStatus}
/> />
) : null} ) : null}
<div className="flex w-full flex-col items-center gap-[10px] sm:gap-[20px]"> <div className="flex w-full flex-col items-center gap-[10px] sm:gap-[20px]">
{winnersCount > 1 ? ( {winnersCount > 1 ? <GradientTitle title="победители" size="small" /> : null}
<GradientTitle title="победители" size="small" />
) : null}
{participantsData && participantsData[0].votes_count > 0 ? ( {participantsData && participantsData[0].votes_count > 0 ? (
<div className="flex flex-col items-center overflow-hidden bg-fillNavyBlue rounded-[10px] sm:rounded-[30px] max-w-[940px] w-full px-[5px] py-[20px] sm:p-[20px] sm:gap-[20px] gap-[10px]"> <div className="flex flex-col items-center overflow-hidden bg-fillNavyBlue rounded-[10px] sm:rounded-[30px] max-w-[940px] w-full px-[5px] py-[20px] sm:p-[20px] sm:gap-[20px] gap-[10px]">
{participantsData.map((participant, index) => {participantsData.map((participant, index) =>
participant.votes_count === participant.votes_count === participantsData[0].votes_count ? (
participantsData[0].votes_count ? (
participant.url ? ( participant.url ? (
<Link <Link
href={participant.url ? participant.url : ""} href={participant.url ? participant.url : ''}
target="_blank" target="_blank"
className="w-full" className="w-full"
key={v4()} key={v4()}>
>
<ParticipantCard <ParticipantCard
index={index} index={index}
hasUrl={true} hasUrl={true}
voteStatus={voteStatus ? voteStatus : ""} voteStatus={voteStatus ? voteStatus : ''}
isFirst={index === 0 ? true : false} isFirst={index === 0 ? true : false}
name={participant.title} name={participant.title}
progress={participant.votes_percents} progress={participant.votes_percents}
@ -284,7 +279,7 @@ const ParticipantsList = ({ vote_id }: IParams) => {
key={v4()} key={v4()}
index={index} index={index}
hasUrl={false} hasUrl={false}
voteStatus={voteStatus ? voteStatus : ""} voteStatus={voteStatus ? voteStatus : ''}
isFirst={index === 0 ? true : false} isFirst={index === 0 ? true : false}
name={participant.title} name={participant.title}
progress={participant.votes_percents} progress={participant.votes_percents}
@ -296,14 +291,12 @@ const ParticipantsList = ({ vote_id }: IParams) => {
winner={true} winner={true}
/> />
) )
) : null ) : null,
)} )}
</div> </div>
) : null} ) : null}
{winnersCount > 1 ? ( {winnersCount > 1 ? <div className="w-full h-[1px] bg-[#3636A3]"></div> : null}
<div className="w-full h-[1px] bg-[#3636A3]"></div>
) : null}
</div> </div>
<div className="flex flex-col items-center max-w-[940px] w-full gap-5 justify-center mx-auto"> <div className="flex flex-col items-center max-w-[940px] w-full gap-5 justify-center mx-auto">
@ -312,15 +305,14 @@ const ParticipantsList = ({ vote_id }: IParams) => {
!hasVotes ? ( !hasVotes ? (
participant.url ? ( participant.url ? (
<Link <Link
href={participant.url ? participant.url : ""} href={participant.url ? participant.url : ''}
target="_blank" target="_blank"
className="w-full mx-auto" className="w-full mx-auto"
key={v4()} key={v4()}>
>
<ParticipantCard <ParticipantCard
index={index} index={index}
hasUrl={true} hasUrl={true}
voteStatus={voteStatus ? voteStatus : ""} voteStatus={voteStatus ? voteStatus : ''}
isFirst={index === 0 ? true : false} isFirst={index === 0 ? true : false}
name={participant.title} name={participant.title}
progress={participant.votes_percents} progress={participant.votes_percents}
@ -337,7 +329,7 @@ const ParticipantsList = ({ vote_id }: IParams) => {
hasUrl={false} hasUrl={false}
key={v4()} key={v4()}
index={index} index={index}
voteStatus={voteStatus ? voteStatus : ""} voteStatus={voteStatus ? voteStatus : ''}
isFirst={index === 0 ? true : false} isFirst={index === 0 ? true : false}
name={participant.title} name={participant.title}
progress={participant.votes_percents} progress={participant.votes_percents}
@ -350,19 +342,17 @@ const ParticipantsList = ({ vote_id }: IParams) => {
/> />
) )
) : ( ) : (
participant.votes_count !== participant.votes_count !== participantsData[0].votes_count &&
participantsData[0].votes_count &&
(participant.url ? ( (participant.url ? (
<Link <Link
href={participant.url ? participant.url : ""} href={participant.url ? participant.url : ''}
target="_blank" target="_blank"
className="w-full mx-auto" className="w-full mx-auto"
key={v4()} key={v4()}>
>
<ParticipantCard <ParticipantCard
index={index} index={index}
hasUrl={true} hasUrl={true}
voteStatus={voteStatus ? voteStatus : ""} voteStatus={voteStatus ? voteStatus : ''}
isFirst={index === 0 ? true : false} isFirst={index === 0 ? true : false}
name={participant.title} name={participant.title}
progress={participant.votes_percents} progress={participant.votes_percents}
@ -379,7 +369,7 @@ const ParticipantsList = ({ vote_id }: IParams) => {
hasUrl={false} hasUrl={false}
key={v4()} key={v4()}
index={index} index={index}
voteStatus={voteStatus ? voteStatus : ""} voteStatus={voteStatus ? voteStatus : ''}
isFirst={index === 0 ? true : false} isFirst={index === 0 ? true : false}
name={participant.title} name={participant.title}
progress={participant.votes_percents} progress={participant.votes_percents}
@ -391,7 +381,7 @@ const ParticipantsList = ({ vote_id }: IParams) => {
winner={false} winner={false}
/> />
)) ))
) ),
) )
: null} : null}
</div> </div>