проработай интерфейс
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Децентрализованный P2P Чат</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f2f2f2;
            display: flex;
            flex-direction: column;
            align-items: center;
            margin: 0;
            padding: 20px;
        }

        h1 {
            color: #333;
        }

        .container {
            background-color: #fff;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            width: 500px;
            margin-top: 20px;
        }

        .section {
            margin-bottom: 15px;
        }

        label {
            display: block;
            margin-bottom: 5px;
            color: #555;
        }

        input[type="text"], input[type="password"] {
            width: calc(100% - 12px);
            padding: 5px;
            border: 1px solid #ccc;
            border-radius: 4px;
        }

        button {
            padding: 7px 15px;
            border: none;
            border-radius: 4px;
            background-color: #4CAF50;
            color: white;
            cursor: pointer;
            margin-top: 5px;
        }

        button:hover {
            background-color: #45a049;
        }

        #messages {
            width: 100%;
            height: 300px;
            overflow-y: scroll;
            border: 1px solid #ccc;
            padding: 10px;
            background-color: #f9f9f9;
            border-radius: 4px;
        }

        #online-users {
            list-style-type: none;
            padding: 0;
            max-height: 100px;
            overflow-y: auto;
            border: 1px solid #ccc;
            border-radius: 4px;
            background-color: #fafafa;
        }

        #online-users li {
            padding: 5px 10px;
            border-bottom: 1px solid #eee;
            color: #333;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        #online-users li:last-child {
            border-bottom: none;
        }

        a.file-link {
            display: block;
            margin-top: 5px;
            color: #0066cc;
            text-decoration: none;
        }

        a.file-link:hover {
            text-decoration: underline;
        }

        /* Стили для окна звонка */
        .call-window {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: #fff;
            padding: 20px;
            border: 2px solid #4CAF50;
            border-radius: 8px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
            display: none;
            z-index: 1000;
        }

        .call-window.active {
            display: block;
        }

        .call-window button {
            background-color: #f44336;
        }

        .hidden {
            display: none;
        }
    </style>
</head>
<body>
    <h1>Децентрализованный P2P Чат</h1>
    <div class="container">
        <div class="section">
            <p>Ваш Peer ID: <span id="peer-id">Подключение...</span></p>
        </div>
        <div class="section">
            <label for="remote-id">Peer ID для подключения:</label>
            <input type="text" id="remote-id" placeholder="Введите Peer ID другого пользователя">
            <button id="connect-btn">Подключиться</button>
        </div>
        <div class="section">
            <h3>Онлайн пользователи:</h3>
            <ul id="online-users">
                <!-- Список онлайн пользователей будет здесь -->
            </ul>
        </div>
        <div class="section">
            <div id="messages"></div>
        </div>
        <div class="section">
            <input type="text" id="message-input" placeholder="Введите сообщение" style="width: 80%;">
            <button id="send-btn">Отправить</button>
        </div>
        <div class="section">
            <input type="file" id="file-input">
            <button id="send-file-btn">Отправить файл</button>
        </div>
        <!-- Новая секция для звонков -->
        <div class="section">
            <button id="call-btn">Позвонить</button>
        </div>
    </div>

    <!-- Окно звонка -->
    <div class="call-window" id="call-window">
        <p id="call-status">Входящий звонок от <span id="caller-id"></span></p>
        <button id="accept-call-btn">Принять</button>
        <button id="reject-call-btn">Отклонить</button>
    </div>

    <!-- Подключение необходимых библиотек через CDN -->
    <script src="https://unpkg.com/peerjs@1.4.7/dist/peerjs.min.js"></script>
    <script>
        // Инициализация Peer
        const peer = new Peer();

        // Элементы интерфейса
        const peerIdDisplay = document.getElementById('peer-id');
        const connectBtn = document.getElementById('connect-btn');
        const remoteIdInput = document.getElementById('remote-id');
        const messagesArea = document.getElementById('messages');
        const sendBtn = document.getElementById('send-btn');
        const messageInput = document.getElementById('message-input');
        const onlineUsersList = document.getElementById('online-users');
        const fileInput = document.getElementById('file-input');
        const sendFileBtn = document.getElementById('send-file-btn');
        const callBtn = document.getElementById('call-btn');

        // Элементы окна звонка
        const callWindow = document.getElementById('call-window');
        const callerIdSpan = document.getElementById('caller-id');
        const acceptCallBtn = document.getElementById('accept-call-btn');
        const rejectCallBtn = document.getElementById('reject-call-btn');

        // Хранение соединений
        let connections = {};
        let currentCall = null;
        let localStream = null;

        // Отображение вашего Peer ID
        peer.on('open', (id) => {
            peerIdDisplay.textContent = id;
            addOnlineUser(id);
        });

        // Обработка входящих соединений
        peer.on('connection', (connection) => {
            if (connections[connection.peer]) {
                connection.close();
                return;
            }
            connections[connection.peer] = connection;
            setupConnection(connection);
            addOnlineUser(connection.peer);
        });

        // Обработка входящих звонков
        peer.on('call', (call) => {
            // Показываем окно звонка
            callWindow.classList.add('active');
            callerIdSpan.textContent = call.peer;

            // Принять звонок
            acceptCallBtn.onclick = () => {
                navigator.mediaDevices.getUserMedia({ audio: true, video: false })
                    .then(stream => {
                        localStream = stream;
                        call.answer(stream);
                        setupCall(call);
                        callWindow.classList.remove('active');
                    })
                    .catch(err => {
                        console.error('Ошибка доступа к микрофону:', err);
                        alert('Не удалось получить доступ к микрофону.');
                    });
            };

            // Отклонить звонок
            rejectCallBtn.onclick = () => {
                call.close();
                callWindow.classList.remove('active');
                appendMessage(`Вы отклонили звонок от ${call.peer}.`);
            };
        });

        // Обработка ошибок
        peer.on('error', (err) => {
            console.error(err);
            alert('Произошла ошибка: ' + err);
        });

        // Функция подключения к другому Peer
        connectBtn.addEventListener('click', () => {
            const remoteId = remoteIdInput.value.trim();

            if (!remoteId) {
                alert('Введите Peer ID для подключения.');
                return;
            }

            // Проверяем, нет ли уже соединения с этим Peer
            if (connections[remoteId]) {
                alert('Уже подключены к этому Peer.');
                return;
            }

            const conn = peer.connect(remoteId);

            connections[remoteId] = conn;

            conn.on('open', () => {
                setupConnection(conn);
                addOnlineUser(remoteId);
                appendMessage(`Установлено соединение с ${remoteId}.`);
            });

            conn.on('error', (err) => {
                console.error('Соединение ошибка:', err);
                appendMessage(`Ошибка соединения с ${remoteId}: ${err}`);
                delete connections[remoteId];
            });
        });

        // Функция настройки соединения
        function setupConnection(conn) {
            conn.on('data', (data) => {
                try {
                    const parsedData = JSON.parse(data);
                    if (parsedData.type === 'message') {
                        appendMessage(`Друг: ${parsedData.content}`);
                    } else if (parsedData.type === 'file') {
                        handleIncomingFile(parsedData);
                    }
                } catch (e) {
                    console.error('Ошибка при разборе данных:', e);
                    appendMessage(`Друг: ${data}`);
                }
            });

            conn.on('close', () => {
                appendMessage(`Соединение с ${conn.peer} закрыто.`);
                removeOnlineUser(conn.peer);
                delete connections[conn.peer];
            });

            // Отправка уведомления о подключении
            appendMessage(`Соединение с ${conn.peer} установлено.`);
        }

        // Функция добавления сообщения в область сообщений
        function appendMessage(message) {
            const messageDiv = document.createElement('div');
            messageDiv.textContent = message;
            messagesArea.appendChild(messageDiv);
            messagesArea.scrollTop = messagesArea.scrollHeight;
        }

        // Обработка отправки текстовых сообщений
        sendBtn.addEventListener('click', () => {
            const message = messageInput.value.trim();
            if (!message) return;

            const data = JSON.stringify({ type: 'message', content: message });

            let hasOpenConnections = false;

            Object.values(connections).forEach((conn) => {
                if (conn.open) {
                    conn.send(data);
                    hasOpenConnections = true;
                }
            });

            if (hasOpenConnections) {
                appendMessage(`Вы: ${message}`);
                messageInput.value = '';
            } else {
                alert('Нет открытых соединений для отправки сообщения.');
            }
        });

        // Функции для обновления списка онлайн-пользователей
        function addOnlineUser(userId) {
            // Проверяем, есть ли уже пользователь в списке
            if (![...onlineUsersList.children].some(li => li.textContent.startsWith(userId))) {
                const li = document.createElement('li');
                li.textContent = userId;

                // Добавляем кнопку звонка рядом с ID пользователя
                if (userId !== peer.id) { // Не отображать кнопку для самого себя
                    const callButton = document.createElement('button');
                    callButton.textContent = 'Позвонить';
                    callButton.style.marginLeft = '10px';
                    callButton.style.padding = '5px 10px';
                    callButton.style.backgroundColor = '#2196F3';
                    callButton.style.color = '#fff';
                    callButton.style.border = 'none';
                    callButton.style.borderRadius = '4px';
                    callButton.style.cursor = 'pointer';
                    callButton.onclick = () => initiateCall(userId);
                    li.appendChild(callButton);
                }

                onlineUsersList.appendChild(li);
                appendMessage(`${userId} подключился.`);
            }
        }

        function removeOnlineUser(userId) {
            [...onlineUsersList.children].forEach(li => {
                if (li.textContent.startsWith(userId)) {
                    onlineUsersList.removeChild(li);
                    appendMessage(`${userId} отключился.`);
                }
            });
        }

        // Обработка отправки файлов
        sendFileBtn.addEventListener('click', () => {
            const file = fileInput.files[0];
            if (!file) {
                alert('Пожалуйста, выберите файл для отправки.');
                return;
            }

            const reader = new FileReader();
            reader.onload = () => {
                const arrayBuffer = reader.result;
                const base64String = arrayBufferToBase64(arrayBuffer);

                const data = JSON.stringify({
                    type: 'file',
                    content: base64String,
                    fileName: file.name,
                    fileType: file.type
                });

                let hasOpenConnections = false;

                Object.values(connections).forEach((conn) => {
                    if (conn.open) {
                        conn.send(data);
                        hasOpenConnections = true;
                    }
                });

                if (hasOpenConnections) {
                    appendMessage(`Вы отправили файл: ${file.name}`);
                    fileInput.value = ''; // Очистка поля выбора файла
                } else {
                    alert('Нет открытых соединений для отправки файла.');
                }
            };
            reader.readAsArrayBuffer(file);
        });

        // Функция обработки входящих файлов
        function handleIncomingFile(data) {
            const { content, fileName, fileType } = data;
            try {
                const arrayBuffer = base64ToArrayBuffer(content);
                const blob = new Blob([arrayBuffer], { type: fileType });

                // Создаем ссылку для скачивания файла
                const link = document.createElement('a');
                const url = URL.createObjectURL(blob);
                link.href = url;
                link.download = fileName;
                link.textContent = `Скачать файл: ${fileName}`;
                link.className = 'file-link';
                link.target = '_blank';

                // Добавляем ссылку в область сообщений
                const fileMessage = document.createElement('div');
                fileMessage.innerHTML = `Друг отправил файл: ${fileName}<br>`;
                fileMessage.appendChild(link);
                messagesArea.appendChild(fileMessage);
                messagesArea.scrollTop = messagesArea.scrollHeight;
            } catch (e) {
                console.error('Ошибка при получении файла:', e);
                appendMessage(`Ошибка при получении файла: ${fileName}`);
            }
        }

        // Вспомогательные функции для преобразования ArrayBuffer в Base64 и обратно
        function arrayBufferToBase64(buffer) {
            let binary = '';
            const bytes = new Uint8Array(buffer);
            const len = bytes.byteLength;
            for (let i = 0; i < len; i++) {
                binary += String.fromCharCode(bytes[i]);
            }
            return window.btoa(binary);
        }

        function base64ToArrayBuffer(base64) {
            const binary_string = window.atob(base64);
            const len = binary_string.length;
            const bytes = new Uint8Array(len);
            for (let i = 0; i < len; i++) {
                bytes[i] = binary_string.charCodeAt(i);
            }
            return bytes.buffer;
        }

        // Функции для звонков
        function initiateCall(peerId) {
            navigator.mediaDevices.getUserMedia({ audio: true, video: false })
                .then(stream => {
                    localStream = stream;
                    const call = peer.call(peerId, stream);
                    setupCall(call);
                    appendMessage(`Вы позвонили ${peerId}.`);
                })
                .catch(err => {
                    console.error('Ошибка доступа к микрофону:', err);
                    alert('Не удалось получить доступ к микрофону.');
                });
        }

        function setupCall(call) {
            if (currentCall) {
                currentCall.close();
            }
            currentCall = call;

            call.on('stream', (remoteStream) => {
                // Создание аудио элемента для воспроизведения входящего аудио
                const audio = document.createElement('audio');
                audio.srcObject = remoteStream;
                audio.autoplay = true;
                audio.controls = true;
                messagesArea.appendChild(audio);
                messagesArea.scrollTop = messagesArea.scrollHeight;
            });

            call.on('close', () => {
                appendMessage('Звонок завершен.');
            });

            call.on('error', (err) => {
                console.error('Ошибка звонка:', err);
                appendMessage('Произошла ошибка во время звонка.');
            });
        }

        // Кнопка для инициирования звонка (альтернативный способ)
        callBtn.addEventListener('click', () => {
            const remoteId = remoteIdInput.value.trim();

            if (!remoteId) {
                alert('Введите Peer ID для звонка.');
                return;
            }

            if (remoteId === peer.id) {
                alert('Вы не можете звонить себе.');
                return;
            }

            initiateCall(remoteId);
        });
    </script>
</body>
</html>