const express = require("express");
const bodyParser = require("body-parser");
const multer = require("multer");
const cors = require("cors");
require("dotenv").config();
const fs = require("fs");
const http = require("http");

const app = express();
const PORT = process.env.PORT || 8080;
app.use(
    cors({
        origin: "*",
        methods: ["GET", "POST", "PUT", "DELETE"],
        allowedHeaders: ["Content-Type", "Authorization"],
        maxAge: 3600,
    })
);

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
const server = http.createServer(app);

const io = require("socket.io")(server, {
    cors: {
        origin: "*",
        methods: ["GET", "POST"],
    },
    transports: ["websocket", "polling"],
});
let users = [];
let cornerSectors = [];

const storage = multer.memoryStorage();
const upload = multer({ storage: storage });
app.get("/", (req, res) => {
    res.send("It`s my server");
});

app.post("/api/upload_photo", upload.single("photo"), (req, res) => {
    const fileBuffer = req.file.buffer;
    const filePath = "./uploads/bg.png";
    fs.writeFileSync(filePath, fileBuffer);
    console.log(`Файл сохранен: ${filePath}`);
    res.send("Файл сохранен!");
});

app.get("/api/get_photo", (req, res) => {
    const filePath = "./uploads/bg.png";
    console.log("success");
    fs.readFile(filePath, (err, data) => {
        if (err) {
            res.status(404).send("Фото не найдено");
        } else {
            res.set("Content-Type", "image/png");
            res.send(data);
        }
    });
});

app.post("/api/cornerSectors", (req, res) => {
    cornerSectors = req.body;
    res.sendStatus(200);
});

app.post("/api/data", (req, res) => {
    const data = req.body;
    users = data.map((row, index) => ({
        user_name: row[0],
        code: row[1].toString(),
        player_id: row[2],
        total_user_points: 0,
        total_user_fish: 0,
        circles: row.slice(3).map((pair, i) => {
            const [opponent_number, sector] = pair;
            const opponent = data.find((r) => r[2] === opponent_number) || {};
            const opponent_name = opponent[0] || "Unknown Opponent";
            return {
                number: i + 1,
                status: i === 0 ? "active" : "inactive",
                index_circle: i + 1,
                second_circle: false,
                playerGame: {
                    approveState: 1,
                    number: row[2],
                    name: row[0],
                    fishCount: null,
                    points: 0,
                    total_points: 0,
                    sector: sector,
                },
                opponentGame: {
                    approveState: 1,
                    number: opponent_number,
                    name: opponent_name,
                    fishCount: null,
                    points: 0,
                    sector: sector,
                    total_points: 0,
                },
            };
        }),
    }));

    const usersWithEmptyName = users.filter(
        (user) => user.user_name === "Empty"
    );

    if (usersWithEmptyName.length > 0) {
        let finalNewUsers = users.map((user) => ({ ...user, circles: [] }));

        for (let i = 0; i < users[0].circles.length; i++) {
            let newUsers = users.map((user) => ({ ...user, circles: [] }));
            for (let j = 0; j < newUsers.length; j++) {
                const circle = users[j].circles[i];
                const newCircle = {
                    number: i + 1,
                    status: i === 0 ? "active" : "inactive",
                    index_circle: i + 1,
                    second_circle: false,
                    playerGame: circle.playerGame,
                    opponentGame: circle.opponentGame,
                };
                newUsers[j].circles.push(newCircle);
            }
            for (let j = 0; j < newUsers.length; j++) {
                const user = newUsers[j];
                const circle = newUsers[j].circles[0];
                if (circle.opponentGame.name === "Empty") {
                    const sectorEmpty = circle.opponentGame.sector;
                    const changeSectorEmpty = cornerSectors.includes(
                        sectorEmpty
                    )
                        ? 1
                        : -1;
                    let userNewOpponent;
                    let userNewOpponentIndex;
                    for (let k = 0; k < newUsers.length; k++) {
                        const opponent = newUsers[k];
                        if (
                            changeSectorEmpty === -1 &&
                            opponent.circles[0].playerGame.sector ===
                                sectorEmpty - 1 &&
                            opponent.player_id % 2 !== (i + 1) % 2
                        ) {
                            userNewOpponent = opponent;
                            userNewOpponentIndex = k;
                            break;
                        }
                    }
                    if (!userNewOpponent) {
                        for (let k = 0; k < newUsers.length; k++) {
                            const opponent = newUsers[k];
                            if (
                                changeSectorEmpty === 1 &&
                                opponent.circles[0].playerGame.sector ===
                                    sectorEmpty + 1 &&
                                opponent.player_id % 2 === (i + 1) % 2
                            ) {
                                userNewOpponent = opponent;
                                userNewOpponentIndex = k;
                                break;
                            }
                        }
                    }

                    if (userNewOpponent) {
                        const newCircleOpponent = {
                            number: i + 1,
                            index_circle: i + 1,
                            second_circle: true,
                            status: i === 0 ? "active" : "inactive",
                            playerGame: userNewOpponent.circles[0].playerGame,
                            opponentGame: circle.playerGame,
                        };
                        newUsers[userNewOpponentIndex].circles.push(
                            newCircleOpponent
                        );
                        newUsers[j].circles[0].opponentGame =
                            userNewOpponent.circles[0].playerGame;
                    } else {
                        console.log(
                            "Не найден оппонент для пользователя",
                            user.user_name
                        );
                    }
                }
            }
            for (let j = 0; j < newUsers.length; j++) {
                for (let k = 0; k < newUsers[j].circles.length; k++) {
                    finalNewUsers[j].circles.push(newUsers[j].circles[k]);
                }
            }
        }
        for (let j = 0; j < finalNewUsers.length; j++) {
            for (let k = 0; k < finalNewUsers[j].circles.length; k++) {
                const circle = finalNewUsers[j].circles[k];
                const newCircle = {
                    number: k + 1,
                    index_circle: circle.index_circle,
                    second_circle: circle.second_circle,
                    status: circle.status,
                    playerGame: circle.playerGame,
                    opponentGame: circle.opponentGame,
                };
                finalNewUsers[j].circles[k] = newCircle;
            }
        }
        users = finalNewUsers;
    }
    res.sendStatus(200);
});

app.get("/api/users", (req, res) => {
    res.json(users);
});

app.get("/api/user/:code", (req, res) => {
    const code = req.params.code.toString();
    const user = users.find((user) => user.code === code);
    console.log("success");
    if (user) {
        res.json(user);
    } else {
        res.status(404).json({ message: "Пользователь не найден" });
    }
});

app.get("/api/unready_players", (req, res) => {
    const usersForUnreadyPlayers = [...users];
    const unreadyPlayers = usersForUnreadyPlayers
        .filter(
            (user) =>
                user.user_name !== "Empty" &&
                user.circles.some(
                    (circle) =>
                        circle.status === "active" &&
                        circle.playerGame.approveState !== 4 &&
                        circle.playerGame.approveState !== 2
                )
        )
        .map((user) => `#${user.player_id} ${user.user_name}`);

    if (unreadyPlayers.length > 0) {
        res.json(unreadyPlayers);
    } else {
        res.json({ message: "Нет неготовых игроков" });
    }
});

app.get("/api/stats", (req, res) => {
    const usersStats = [...users];
    const resultArray = usersStats
        .filter((user) => user.user_name !== "Empty")
        .map((user) => {
            const circlePoints = user.circles
                .filter((circle) => !circle.second_circle)
                .map((circle) => circle.playerGame.points);
            return [
                user.player_id,
                user.user_name,
                user.total_user_points,
                user.total_user_fish,
                ...circlePoints,
            ];
        })
        .sort((a, b) => {
            if (a[2] === b[2]) {
                return b[3] - a[3];
            } else {
                return b[2] - a[2];
            }
        });

    res.json(resultArray);
});

app.get("/api/circles", (req, res) => {
    res.json(users.map((user) => user.circles));
});

app.post("/api/update-score", (req, res) => {
    const { userData, activeCircleNumber } = req.body;
    let updatedUserData = userData;
    const circle = updatedUserData.circles.find(
        (circle) => circle.number === activeCircleNumber
    );
    const userIndex = users.findIndex(
        (user) => user.code === updatedUserData.code
    );
    if (userIndex === -1) {
        return res.status(404).json({ message: "User not found" });
    }
    users[userIndex] = updatedUserData;
    const opponentIndex = users.findIndex(
        (user) => user.player_id === circle.opponentGame.number
    );
    if (opponentIndex !== -1) {
        const opponentCircleIndex = users[opponentIndex].circles.findIndex(
            (c) =>
                c.opponentGame.number === updatedUserData.player_id &&
                c.status === "active"
        );
        if (opponentCircleIndex !== -1) {
            users[opponentIndex].circles[
                opponentCircleIndex
            ].opponentGame.fishCount = circle.playerGame.fishCount;
        }
    }
    updatedUserData = users[userIndex];
    io.emit("userUpdated", { updatedUserData, activeCircleNumber });

    res.sendStatus(200);
});

app.post("/api/update-approve-state", (req, res) => {
    const { userData, activeCircleNumber } = req.body;
    let updatedUserData = userData;
    let needToCheckNewTour = false;
    const circle = updatedUserData.circles.find(
        (c) => c.number === activeCircleNumber
    );
    const userIndex = users.findIndex(
        (user) => user.code === updatedUserData.code
    );
    const opponentIndex = users.findIndex(
        (user) => user.player_id === circle.opponentGame.number
    );
    if (opponentIndex !== -1) {
        const opponent = users[opponentIndex];
        const opponentCircleIndex = opponent.circles.findIndex(
            (c) =>
                c.opponentGame.number === updatedUserData.player_id &&
                c.status === "active"
        );
        const playerCircleIndex = updatedUserData.circles.findIndex(
            (c) => c.number === circle.number
        );
        if (opponentCircleIndex !== -1) {
            opponent.circles[opponentCircleIndex].opponentGame.approveState =
                circle.playerGame.approveState;
            users[opponentIndex] = opponent;
            let playerApproveState = circle.playerGame.approveState;
            let playerOppApproveState = circle.playerGame.approveState;
            let opponentApproveState =
                opponent.circles[opponentCircleIndex].playerGame.approveState;
            let opponentOppApproveState =
                opponent.circles[opponentCircleIndex].opponentGame.approveState;

            if (playerApproveState === 1 && opponentApproveState === 1) {
                playerApproveState = 2;
                playerOppApproveState = 3;

                opponentApproveState = 3;
                opponentOppApproveState = 2;
            } else if (playerApproveState === 2 && opponentApproveState === 3) {
                playerApproveState = 1;
                playerOppApproveState = 1;

                opponentApproveState = 1;
                opponentOppApproveState = 1;
            } else if (playerApproveState === 3 && opponentApproveState === 2) {
                playerApproveState = 4;
                playerOppApproveState = 4;

                opponentApproveState = 4;
                opponentOppApproveState = 4;
                needToCheckNewTour = true;
            } else if (playerApproveState === 4 && opponentApproveState === 4) {
                playerApproveState = 3;
                playerOppApproveState = 2;

                opponentApproveState = 2;
                opponentOppApproveState = 3;
            } else {
                playerApproveState = 1;
                playerOppApproveState = 1;

                opponentApproveState = 1;
                opponentOppApproveState = 1;
            }
            users[userIndex].circles = users[userIndex].circles.map(
                (circle, index) => {
                    if (index === playerCircleIndex) {
                        return {
                            ...circle,
                            playerGame: {
                                ...circle.playerGame,
                                approveState: playerApproveState,
                            },
                            opponentGame: {
                                ...circle.opponentGame,
                                approveState: playerOppApproveState,
                            },
                        };
                    }
                    return circle;
                }
            );

            users[opponentIndex].circles = users[opponentIndex].circles.map(
                (circle, index) => {
                    if (index === opponentCircleIndex) {
                        return {
                            ...circle,
                            playerGame: {
                                ...circle.playerGame,
                                approveState: opponentApproveState,
                            },
                            opponentGame: {
                                ...circle.opponentGame,
                                approveState: opponentOppApproveState,
                            },
                        };
                    }
                    return circle;
                }
            );

            updatedUserData = { ...users[userIndex] };
        } else {
            console.error(
                `Active circle not found for opponent with player_id ${circle.opponentGame.number}`
            );
        }
    } else {
        console.error(
            `Opponent with player_id ${circle.opponentGame.number} not found`
        );
    }
    io.emit("userUpdated", { updatedUserData, activeCircleNumber });
    if (needToCheckNewTour) {
        checkAndUpdateRoundStatus();
    }
    res.sendStatus(200);
});

io.on("connection", (socket) => {
    socket.on("userUpdate", (data) => {
        const { updatedUserData, activeCircleNumber } = data;
        io.emit("userUpdated", { updatedUserData, activeCircleNumber });
    });

    socket.on("allUsersUpdated", (users) => {
        io.emit("allUsersUpdated", users);
    });

    socket.on("disconnect", () => {});
});

function checkAndUpdateRoundStatus() {
    let allCirclesApproved = true;
    users.forEach((user) => {
        user.circles.forEach((circle) => {
            if (
                circle.status === "active" &&
                circle.playerGame.approveState !== 4 &&
                circle.playerGame.name !== "Empty"
            ) {
                allCirclesApproved = false;
            }
        });
    });
    if (allCirclesApproved) {
        users.forEach((user, userIndex) => {
            const activeCircleIndex = user.circles.findIndex(
                (c) => c.status === "active"
            );
            if (activeCircleIndex !== -1) {
                let newRoundPoints = 0;
                const playerFish =
                    user.circles[activeCircleIndex].playerGame.fishCount;
                const opponentFish =
                    user.circles[activeCircleIndex].opponentGame.fishCount;
                if (playerFish === 0 && opponentFish === 0) {
                    newRoundPoints = 1;
                } else if (playerFish === opponentFish && playerFish > 0) {
                    newRoundPoints = 2;
                } else if (playerFish > opponentFish) {
                    newRoundPoints = 4;
                } else if (playerFish < opponentFish && playerFish > 0) {
                    newRoundPoints = 1;
                } else if (playerFish < opponentFish && playerFish === 0) {
                    newRoundPoints = 0;
                }
                users[userIndex].total_user_points =
                    users[userIndex].total_user_points + newRoundPoints;
                users[userIndex].total_user_fish =
                    users[userIndex].total_user_fish + playerFish;
                users[userIndex].circles[activeCircleIndex].playerGame.points =
                    newRoundPoints;
                users[userIndex].circles[
                    activeCircleIndex
                ].playerGame.total_points = users[userIndex].total_user_points;
                users.forEach((userOpponent, userIndexOpponent) => {
                    userOpponent.circles.forEach(
                        (circleOpponent, circleIndexOpponent) => {
                            if (
                                circleOpponent.opponentGame.number ===
                                user.player_id
                            ) {
                                if (circleOpponent.status === "active") {
                                    users[userIndexOpponent].circles[
                                        circleIndexOpponent
                                    ].opponentGame.points =
                                        users[userIndex].circles[
                                            activeCircleIndex
                                        ].playerGame.points;
                                }
                                users[userIndexOpponent].circles[
                                    circleIndexOpponent
                                ].opponentGame.total_points =
                                    users[userIndex].circles[
                                        activeCircleIndex
                                    ].playerGame.total_points;
                            } else if (
                                circleOpponent.playerGame.number ===
                                user.player_id
                            ) {
                                users[userIndexOpponent].circles[
                                    circleIndexOpponent
                                ].playerGame.total_points =
                                    users[userIndex].circles[
                                        activeCircleIndex
                                    ].playerGame.total_points;
                            }
                        }
                    );
                });
            }
        });
        /*
        Выше я для каждого пользователя сначала обновил его очки и рыбы глобально, затем всем его оппонентам в кругах обновил его данные об общих очках
        И если мы встретили текущего оппонента, ему обновляем наши points текущие для этого раунда
        Таким образом мы каждому игроку обновили его глобальные данные, данные в его кругах, данные о нем в кругах всех его оппонентов
        И после прохода по всем игрокам будет обновлена информация у всех про всех
        Ниже происходит обновление статуса кругов и emit в socket.
        */
        users.forEach((user, userIndex) => {
            const activeCircles = user.circles.filter(
                (c) => c.status === "active"
            );

            // Найти все неактивные круги
            const inactiveCircles = user.circles.filter(
                (c) => c.status === "inactive"
            );

            activeCircles.forEach((activeCircle) => {
                const nextCircleIndex = user.circles.indexOf(activeCircle) + 1;
                let nextInactiveCircleIndex;
                let secondInactiveCircle;
                if (nextCircleIndex < user.circles.length) {
                    const nextCircle = user.circles[nextCircleIndex];
                    if (nextCircle.status === "inactive") {
                        nextInactiveCircleIndex = nextCircleIndex + 1;
                        nextCircle.status = "active";
                        nextCircle.playerGame.approveState = 1;
                        nextCircle.opponentGame.approveState = 1;
                        nextCircle.playerGame.fishCount = null;
                        nextCircle.opponentGame.fishCount = null;
                    }
                }

                if (nextInactiveCircleIndex < user.circles.length) {
                    secondInactiveCircle =
                        user.circles[nextInactiveCircleIndex];
                }
                if (
                    secondInactiveCircle &&
                    secondInactiveCircle.second_circle
                ) {
                    if (secondInactiveCircle.status === "inactive") {
                        secondInactiveCircle.status = "active";
                        secondInactiveCircle.playerGame.approveState = 1;
                        secondInactiveCircle.opponentGame.approveState = 1;
                        secondInactiveCircle.playerGame.fishCount = null;
                        secondInactiveCircle.opponentGame.fishCount = null;
                    }
                }
            });

            activeCircles.forEach((activeCircle) => {
                activeCircle.status = "completed";
            });
        });
        io.emit("allUsersUpdated", users);
    }
}

server.listen(PORT, () => {
    console.log(`Server is running on http://localhost:${PORT}`);
});

Это мой сервер
import React, { useState, useEffect } from 'react';
import { useNavigate, useParams, useLocation } from "react-router-dom";
import vectorImage from './images/Vector.png';
import {io} from 'socket.io-client';
import './Tournament.css';

const server_url = process.env.REACT_APP_API_URL;;


const socket = io(`${server_url}`, {
    transports: ['websocket', 'polling'],
    secure: true,
  });

socket.on("connect", () => {
    console.log("Connected to WebSocket server");
});

const Tournament = () => {
    const { code } = useParams();
    const navigate = useNavigate();
    const location = useLocation();
    const { state } = location;
    
    const [activeCircle, setActiveCircle] = useState(null);
    const [playerScoreInput, setPlayerScoreInput] = useState(null);
    const [userData, setUserData] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);

    useEffect(() => {
        const fetchUserData = async () => {
            try {
                const response = await fetch(`${server_url}/api/user/${code}`);
                if (!response.ok) {
                    throw new Error('Network response was not ok');
                }
                const data = await response.json();
                setUserData(data);
                if (state && state.activeCircle && data.circles.find(circle => circle.number === state.activeCircle)) {
                    const newActiveCircle = data.circles.find(circle => circle.number === state.activeCircle);
                    setActiveCircle(newActiveCircle);
                    setPlayerScoreInput(newActiveCircle.playerGame.fishCount);
                  } else {
                    const newActiveCircle = data.circles.find(circle => circle.status === 'active');
                    if (newActiveCircle) {
                      setActiveCircle(newActiveCircle);
                      setPlayerScoreInput(newActiveCircle.playerGame.fishCount);
                    } else {
                      setActiveCircle(data.circles[0]);
                      setPlayerScoreInput(data.circles[0].fishCount);
                    }
                  }
            } catch (error) {
                setError(error.message || 'Unknown error');
            } finally {
                setLoading(false);
            }
        };
        
        fetchUserData();
    }, [code, state]);



    useEffect(() => {
        const handleUserUpdated = (data) => {
            const { updatedUserData, activeCircleNumber } = data;
            if (userData && userData.code === updatedUserData.code) {
                setUserData(updatedUserData);
                const updatedCircle = updatedUserData.circles.find(c => c.number === activeCircleNumber);
                setActiveCircle(updatedCircle);
                setPlayerScoreInput(updatedCircle.playerGame.fishCount);
            } else if (userData) {
                const currUpdatedActiveCircle = updatedUserData.circles.find(circle => circle.number === activeCircleNumber && circle.opponentGame.number === userData.player_id && circle.status === 'active');
                let number = activeCircle.number;
                if (currUpdatedActiveCircle){
                const updatedCircles = userData.circles.map(circle => {
                    const updatedCircle = updatedUserData.circles.find(c => c.status === "active" && c.opponentGame.number === circle.playerGame.number && circle.opponentGame.number === c.playerGame.number && circle.status === 'active');
                    if (updatedCircle) {
                        number = circle.number;
                        return {
                            ...circle,
                            opponentGame: {
                                ...circle.opponentGame,
                                fishCount: updatedCircle.playerGame.fishCount,
                                approveState: updatedCircle.playerGame.approveState,
                            },
                            playerGame: {
                                ...circle.playerGame,
                                fishCount: updatedCircle.opponentGame.fishCount,
                                approveState: updatedCircle.opponentGame.approveState,  
                            } 
                        };
                    }
                    return circle;
                });
                setUserData(prevUserData => ({
                    ...prevUserData,
                    circles: updatedCircles,
                }));
                const newActiveCircle = updatedCircles.find(circle => circle.opponentGame.number === currUpdatedActiveCircle.playerGame.number && circle.playerGame.number === currUpdatedActiveCircle.opponentGame.number && circle.status === 'active');
                setActiveCircle(newActiveCircle);
                setPlayerScoreInput(newActiveCircle.playerGame.fishCount);
                }
            }
        };

        const handleAllUsersUpdated = (updatedUsersData) => {
            const currentUser = updatedUsersData.find(user => user.code === code);
            if (currentUser) {
                setUserData(currentUser);
                let currUpdatedActiveCircle = currentUser.circles.find(circle => circle.status === 'active');
                 if (!currUpdatedActiveCircle) {
                currUpdatedActiveCircle = currentUser.circles.find(circle => circle.number === 1);
                }
                setActiveCircle(currUpdatedActiveCircle);
                setTimeout(() => {
                    setPlayerScoreInput('');
                }, 100);
                console.log(playerScoreInput);
            }
        };
    
        socket.on('allUsersUpdated', handleAllUsersUpdated);
        socket.on('userUpdated', handleUserUpdated);
        return () => {
            socket.off('allUsersUpdated', handleAllUsersUpdated);
            socket.off('userUpdated', handleUserUpdated);
        };
    }, [userData, playerScoreInput, activeCircle]);

    const handleCircleClick = (circle) => {
        setActiveCircle(circle);
        if (circle.status === 'active') setPlayerScoreInput(circle.playerGame.fishCount);
    };

    const navigateToTournament = () => {
        socket.on("disconnect", () => {
            console.log("Disconnected from WebSocket server");
        });
        navigate(`/statistics/${code}`);
    };

    const updateApproveState = async () => {
        if (!activeCircle || activeCircle.status !== "active" || !userData || activeCircle.playerGame.fishCount === null || activeCircle.opponentGame.fishCount === null) return;
        try {
            const response = await fetch(`${server_url}/api/update-approve-state`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({userData: userData, activeCircleNumber: activeCircle.number}),
            });
    
            if (!response.ok) setError('Failed to update approve state');
        } catch (error) {
            setError('Error updating approve state:', error);
        }
    };

    const handleScoreInputChange = (e) => {
        let value = e.target.value;
        if (value === '' || isNaN(value) || parseInt(value) > 99) {
            value = 0;
        } else {
            value = parseInt(value);
        }
        setPlayerScoreInput(value);
    };
    

    const handleScoreInputBlur = async () => {
        let newPlayerScoreInput;
        if (playerScoreInput === '' || isNaN(playerScoreInput)) {
            setPlayerScoreInput(0);
            newPlayerScoreInput = 0;
        } else {
            newPlayerScoreInput = playerScoreInput;
        }
        const activeCircleIndex = userData.circles.findIndex(circle => circle.number === activeCircle.number && circle.status === 'active');
        if (activeCircleIndex !== -1) {
            let updatedUserData = userData;
            updatedUserData.circles[activeCircleIndex].playerGame.fishCount = newPlayerScoreInput;
            setPlayerScoreInput(newPlayerScoreInput);
            setUserData(updatedUserData);
            setActiveCircle( updatedUserData.circles[activeCircleIndex]);
            try {
                const response = await fetch(`${server_url}/api/update-score`, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({userData: userData, activeCircleNumber: activeCircle.number}),
                });
    
                if (response.ok) {

                } else {
                    setError('Failed to update score');
                }
            } catch (error) {
                setError('Error updating score:', error);
            }
        }
    };
    

    if (loading) {
        return <div>Loading...</div>;
    }

    if (error) {
        return <div>Error: {error}</div>;
    }

    return (
        <article className="playerCard">
            <div className='kostul'></div>
            <div className='kostul2'></div>
            <div className='kostul3'></div>
            <div className="mainRectangle"></div>
            <div className="header"></div>
            <div className="triangle"><span>VS</span></div>
            <div className={`redRectangle ${activeCircle?.status === "completed" ? 'completed' : activeCircle?.status === "inactive" ? 'inactive' : ''}`}>
                {`#${activeCircle?.opponentGame.number} ${activeCircle?.opponentGame.name}: ${activeCircle?.opponentGame.total_points} pts`}
            </div>
            <div className="sectorInfo">
                {`Sector ${activeCircle?.playerGame.sector}${(activeCircle?.playerGame.number % 2 === activeCircle?.index_circle % 2) ? 'R' : 'L'}`}
            </div>
            <div
                className={`bottomRectangle ${activeCircle?.status === "inactive" || activeCircle?.status === "completed" ? 'inactive' : `state-${activeCircle?.playerGame.approveState}`}`}
                onClick={updateApproveState}
            >
                {activeCircle?.status === "completed" ? `+ ${activeCircle?.playerGame.points} Pts` : activeCircle?.status === "inactive" ? 'Approve' : activeCircle?.playerGame.approveState === 1 ? 'Approve' : activeCircle.playerGame.approveState === 2 ? 'Disapprove' : activeCircle.playerGame.approveState === 3 ? 'Approve' : 'Disapprove'}
            </div>
            <div className="playerNameContainer">
                <div className="playerName">{`#${activeCircle?.playerGame.number} ${activeCircle?.playerGame.name}: ${activeCircle?.playerGame.total_points} pts`}</div>
                <img src={vectorImage} alt='' className="vectorImage" onClick={navigateToTournament} />
            </div>
            <div className="circleContainerlayout">
                <div className="thickerWhiteLine"></div>
                <div className="circleContainer">
                    {userData.circles.map((circle) => (
                        <div
                            key={circle.number}
                            className={`circle ${circle.status} ${
                                activeCircle?.number === circle.number ? 'highlighted' : ''
                            }`}
                            onClick={() => handleCircleClick(circle)}
                        >
                            <span>{circle.index_circle}</span>
                            <span>
                                {circle.playerGame.fishCount}:{circle.opponentGame.fishCount}
                            </span>
                            {activeCircle?.number === circle.number && (
                                <div className="triangle-under-circle"></div>
                            )}
                        </div>
                    ))}
                </div>
            </div>
            <div className="whiteRectangleLeft">
                <div className="playerNumberLeft">{`#${activeCircle?.playerGame.number}`}</div>
            </div>
            <div className={`blueRectangleLeft ${activeCircle?.status === "completed" ? 'completed' : activeCircle?.status === "inactive" ? 'inactive' : 'active'}`}>
                {activeCircle?.status === "completed" || activeCircle?.status === "inactive" ? (
                    <div className="score">{activeCircle?.playerGame.fishCount}</div>
                ) : (activeCircle?.playerGame.approveState === 1 || activeCircle?.playerGame.approveState === 2) ? (
                    <input
                        type="tel"
                        value={playerScoreInput}
                        onFocus={() => setPlayerScoreInput('')}
                        onChange={handleScoreInputChange}
                        onBlur={handleScoreInputBlur}
                        className="scoreInputActive"
                    />
                ) : (
                    <input
                        type="tel"
                        value={playerScoreInput}
                        readOnly
                        className="scoreInput"
                    />
                )
            }
            </div>
                <div className="whiteRectangleRight">
                    <div className="playerNumberRight">{`#${activeCircle?.opponentGame.number}`}</div>
                </div>
                <div className={`blueRectangleRight ${activeCircle?.status === "completed" ? 'completed' : activeCircle?.status === "inactive" ? 'inactive' : ''}`}>
                    <div className="score">
                    {activeCircle?.opponentGame.fishCount}
                </div>
            </div>
        </article>
    );
};

export default Tournament;
Это мой клиент
Смотри, у меня люди на страницу клиента заходят по адресу /tournament:code, у каждого свой уникальный code, сайт должен работать так, чтобы даже если потерялось соединение, после его восстановления все данные не отправленные с клиентов приходили на сервер, а все неполученные данные с сервера приходили на клиент