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