websocket fix
This commit is contained in:
parent
54256ba2da
commit
9c560f9c99
|
|
@ -26,13 +26,13 @@ const AnimatedText = ({
|
||||||
className={className}
|
className={className}
|
||||||
initial={{ y: initialY, opacity: 0 }}
|
initial={{ y: initialY, opacity: 0 }}
|
||||||
animate={{ y: 0, opacity: 1 }}
|
animate={{ y: 0, opacity: 1 }}
|
||||||
exit={{ y: initialY, opacity: 0 }}>
|
exit={{ y: '100%', opacity: 0 }}>
|
||||||
{words.map((word, i) => (
|
{words.map((word, i) => (
|
||||||
<motion.span
|
<motion.span
|
||||||
key={i}
|
key={i}
|
||||||
initial={{ y: initialY, opacity: 0 }}
|
initial={{ y: initialY, opacity: 0 }}
|
||||||
animate={{ y: 0, opacity: 1 }}
|
animate={{ y: 0, opacity: 1 }}
|
||||||
exit={{ y: initialY, opacity: 0 }}
|
exit={{ y: '100%', opacity: 0 }}
|
||||||
transition={{
|
transition={{
|
||||||
duration,
|
duration,
|
||||||
delay: i * wordDelay,
|
delay: i * wordDelay,
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,13 @@ import LotterySlotCounter from './slotCounter/LotterySlotCounter';
|
||||||
import ReactConfetti from 'react-confetti';
|
import ReactConfetti from 'react-confetti';
|
||||||
import { useWindowSize } from 'react-use';
|
import { useWindowSize } from 'react-use';
|
||||||
import LotteryCountDownAllert from './countDown/countDownAllert/LotteryCountDownAllert';
|
import LotteryCountDownAllert from './countDown/countDownAllert/LotteryCountDownAllert';
|
||||||
import { motion } from 'framer-motion';
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
import AnimatedText from '@/components/common/AnimatedText';
|
import AnimatedText from '@/components/common/AnimatedText';
|
||||||
|
|
||||||
const WEBSOCKET_URL = 'wss://sms.turkmentv.gov.tm/ws/lottery?dst=0506';
|
const WEBSOCKET_URL = 'wss://sms.turkmentv.gov.tm/ws/lottery?dst=0506';
|
||||||
const PING_INTERVAL = 25000;
|
const PING_INTERVAL = 25000;
|
||||||
const SLOT_COUNTER_DURATION = 20000;
|
const SLOT_COUNTER_DURATION = 20000;
|
||||||
|
const RECONNECT_INTERVAL = 5000;
|
||||||
|
|
||||||
const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) => {
|
const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) => {
|
||||||
// UI States
|
// UI States
|
||||||
|
|
@ -29,16 +30,15 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
|
||||||
'not-selected' | 'is-selecting' | 'selected'
|
'not-selected' | 'is-selecting' | 'selected'
|
||||||
>('not-selected');
|
>('not-selected');
|
||||||
const [pendingWinner, setPendingWinner] = useState<LotteryWinnerDataSimplified | null>(null);
|
const [pendingWinner, setPendingWinner] = useState<LotteryWinnerDataSimplified | null>(null);
|
||||||
|
|
||||||
// Refs
|
|
||||||
const wsRef = useRef<WebSocket | null>(null);
|
|
||||||
const pingIntervalRef = useRef<NodeJS.Timeout>();
|
|
||||||
const mountedRef = useRef(false);
|
|
||||||
|
|
||||||
// Add new state for display text
|
// Add new state for display text
|
||||||
const [displayText, setDisplayText] = useState<string>('...');
|
const [displayText, setDisplayText] = useState<string>('...');
|
||||||
const [winnerText, setWinnerText] = useState<string>('');
|
const [winnerText, setWinnerText] = useState<string>('');
|
||||||
|
|
||||||
|
const wsRef = useRef<WebSocket | null>(null);
|
||||||
|
const pingIntervalRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
const mountedRef = useRef(false);
|
||||||
|
|
||||||
// Initialize winners from lottery data
|
// Initialize winners from lottery data
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (lotteryData?.data.winners) {
|
if (lotteryData?.data.winners) {
|
||||||
|
|
@ -52,17 +52,18 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
|
||||||
}
|
}
|
||||||
}, [lotteryData]);
|
}, [lotteryData]);
|
||||||
|
|
||||||
// Handle WebSocket connection
|
// WebSocket Setup
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
mountedRef.current = true;
|
mountedRef.current = true;
|
||||||
|
|
||||||
const setupWebSocket = () => {
|
const setupWebSocket = () => {
|
||||||
|
if (wsRef.current) return; // Prevent duplicate connections
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const socket = new WebSocket(WEBSOCKET_URL);
|
const socket = new WebSocket(WEBSOCKET_URL);
|
||||||
wsRef.current = socket;
|
wsRef.current = socket;
|
||||||
|
|
||||||
socket.addEventListener('open', () => {
|
socket.addEventListener('open', () => {
|
||||||
if (!mountedRef.current) return;
|
|
||||||
console.log('WebSocket Connected');
|
console.log('WebSocket Connected');
|
||||||
setWsStatus('connected');
|
setWsStatus('connected');
|
||||||
|
|
||||||
|
|
@ -73,91 +74,101 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
|
||||||
}, PING_INTERVAL);
|
}, PING_INTERVAL);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.addEventListener('message', async (event) => {
|
socket.addEventListener('message', handleWebSocketMessage);
|
||||||
|
|
||||||
|
socket.addEventListener('error', () => {
|
||||||
|
console.error('WebSocket Error');
|
||||||
|
setWsStatus('error');
|
||||||
|
reconnectWebSocket();
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.addEventListener('close', () => {
|
||||||
|
console.log('WebSocket Closed');
|
||||||
|
setWsStatus('error');
|
||||||
|
reconnectWebSocket();
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error creating WebSocket:', error);
|
||||||
|
setWsStatus('error');
|
||||||
|
reconnectWebSocket();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const reconnectWebSocket = () => {
|
||||||
|
if (reconnectTimeoutRef.current) return; // Prevent multiple reconnect attempts
|
||||||
|
|
||||||
|
reconnectTimeoutRef.current = setTimeout(() => {
|
||||||
|
console.log('Reconnecting WebSocket...');
|
||||||
|
setupWebSocket();
|
||||||
|
reconnectTimeoutRef.current = null;
|
||||||
|
}, RECONNECT_INTERVAL);
|
||||||
|
};
|
||||||
|
|
||||||
|
setupWebSocket();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
mountedRef.current = false;
|
||||||
|
|
||||||
|
if (pingIntervalRef.current) {
|
||||||
|
clearInterval(pingIntervalRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reconnectTimeoutRef.current) {
|
||||||
|
clearTimeout(reconnectTimeoutRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wsRef.current) {
|
||||||
|
wsRef.current.close();
|
||||||
|
wsRef.current = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// WebSocket Message Handler
|
||||||
|
const handleWebSocketMessage = async (event: MessageEvent) => {
|
||||||
if (!mountedRef.current) return;
|
if (!mountedRef.current) return;
|
||||||
console.log('Message received:', event.data);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const newWinner = JSON.parse(event.data);
|
const newWinner = JSON.parse(event.data);
|
||||||
|
if (!newWinner || !newWinner.phone || !newWinner.winner_no || !newWinner.ticket) {
|
||||||
|
throw new Error('Invalid data format received');
|
||||||
|
}
|
||||||
|
|
||||||
const winnerData = {
|
const winnerData = {
|
||||||
client: newWinner.phone,
|
client: newWinner.phone,
|
||||||
winner_no: newWinner.winner_no,
|
winner_no: newWinner.winner_no,
|
||||||
ticket: newWinner.ticket,
|
ticket: newWinner.ticket,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set initial animation text
|
|
||||||
setDisplayText(`${winnerData.winner_no}-nji ýeňiji saýlanýar`);
|
setDisplayText(`${winnerData.winner_no}-nji ýeňiji saýlanýar`);
|
||||||
|
|
||||||
// Start the sequence
|
|
||||||
setWinnerSelectingStatus('is-selecting');
|
setWinnerSelectingStatus('is-selecting');
|
||||||
setPendingWinner(winnerData);
|
setPendingWinner(winnerData);
|
||||||
setCurrentNumber(winnerData.ticket);
|
setCurrentNumber(winnerData.ticket);
|
||||||
|
|
||||||
// Wait for slot counter animation
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, SLOT_COUNTER_DURATION));
|
await new Promise((resolve) => setTimeout(resolve, SLOT_COUNTER_DURATION));
|
||||||
|
|
||||||
// Update text to show winner's phone
|
|
||||||
setDisplayText('The winner is');
|
setDisplayText('The winner is');
|
||||||
setWinnerText(winnerData.client);
|
setWinnerText(winnerData.client);
|
||||||
setWinnerSelectingStatus('selected');
|
setWinnerSelectingStatus('selected');
|
||||||
|
|
||||||
setIsConfettiActive(true);
|
setIsConfettiActive(true);
|
||||||
|
|
||||||
setWinners((prev) => [...prev, winnerData]);
|
setWinners((prev) => [...prev, winnerData]);
|
||||||
|
|
||||||
// Reset everything after 5 seconds
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (mountedRef.current) {
|
if (mountedRef.current) {
|
||||||
setIsConfettiActive(false);
|
setIsConfettiActive(false);
|
||||||
// setIsSlotCounterAnimating(false);
|
|
||||||
setWinnerSelectingStatus('not-selected');
|
setWinnerSelectingStatus('not-selected');
|
||||||
setPendingWinner(null);
|
setPendingWinner(null);
|
||||||
setDisplayText('...'); // Reset text
|
setDisplayText('...');
|
||||||
setWinnerText('');
|
setWinnerText('');
|
||||||
}
|
}
|
||||||
}, 5000);
|
}, 10000);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error processing message:', error);
|
console.error('Error processing message:', error);
|
||||||
setIsSlotCounterAnimating(false);
|
setDisplayText('Error processing winner');
|
||||||
setPendingWinner(null);
|
|
||||||
setDisplayText('...'); // Reset text on error
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.addEventListener('error', (error) => {
|
|
||||||
if (!mountedRef.current) return;
|
|
||||||
console.error('WebSocket Error:', error);
|
|
||||||
setWsStatus('error');
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.addEventListener('close', () => {
|
|
||||||
if (!mountedRef.current) return;
|
|
||||||
console.log('WebSocket Closed');
|
|
||||||
setWsStatus('error');
|
|
||||||
|
|
||||||
if (pingIntervalRef.current) {
|
|
||||||
clearInterval(pingIntervalRef.current);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error creating WebSocket:', error);
|
|
||||||
setWsStatus('error');
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initial connection
|
|
||||||
setupWebSocket();
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
mountedRef.current = false;
|
|
||||||
if (pingIntervalRef.current) {
|
|
||||||
clearInterval(pingIntervalRef.current);
|
|
||||||
}
|
|
||||||
if (wsRef.current) {
|
|
||||||
wsRef.current.close();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
{wsStatus === 'error' && (
|
{wsStatus === 'error' && (
|
||||||
|
|
@ -190,6 +201,7 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
|
||||||
<div
|
<div
|
||||||
className="flex flex-col items-center rounded-[32px] gap-[40px]"
|
className="flex flex-col items-center rounded-[32px] gap-[40px]"
|
||||||
style={{ background: 'linear-gradient(180deg, #F0ECF4 0%, #E1E0FF 43.5%)' }}>
|
style={{ background: 'linear-gradient(180deg, #F0ECF4 0%, #E1E0FF 43.5%)' }}>
|
||||||
|
<AnimatePresence mode="wait">
|
||||||
<div className="flex items-center justify-center w-full min-h-[240px]">
|
<div className="flex items-center justify-center w-full min-h-[240px]">
|
||||||
{winnerSelectingStatus === 'not-selected' ||
|
{winnerSelectingStatus === 'not-selected' ||
|
||||||
winnerSelectingStatus === 'is-selecting' ? (
|
winnerSelectingStatus === 'is-selecting' ? (
|
||||||
|
|
@ -212,7 +224,7 @@ const LotteryWinnersSection = ({ lotteryStatus }: { lotteryStatus: string }) =>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</AnimatePresence>
|
||||||
<div className="z-10">
|
<div className="z-10">
|
||||||
<LotterySlotCounter numberString={currentNumber} isAnimating={isSlotCounterAnimating} />
|
<LotterySlotCounter numberString={currentNumber} isAnimating={isSlotCounterAnimating} />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue