Сообщения не сортируются должным образом в Firebase (JS, HTML)

Вопрос или проблема

Я создал веб-сайт на Firebase с использованием JS и фронтенда

Все работает правильно, за исключением одной вещи. Мои чаты не сортируются по дате корректно
Вот что я вижу сейчас:

Anastasia: Привет! (9/17/2024, 10:46:47 PM)
Anastasia: Как дела? (9/17/2024, 10:47:06 PM)
Anastasia: Привет (9/17/2024, 11:41:27 PM)
User2: Да (9/17/2024, 10:49:16 PM)
User2: Хорошо, спасибо! (9/17/2024, 10:47:23 PM)
User2: Привет (9/17/2024, 10:46:55 PM)

Что я хочу видеть:

User2: Привет (9/17/2024, 10:46:55 PM)
Anastasia: Привет! (9/17/2024, 10:46:47 PM)
Anastasia: Как дела? (9/17/2024, 10:47:06 PM)
User2: Хорошо, спасибо! (9/17/2024, 10:47:23 PM)
User2: Да (9/17/2024, 10:49:16 PM)
Anastasia: Привет (9/17/2024, 11:41:27 PM)

Мой код

document.addEventListener("DOMContentLoaded", () => {
  firebase.auth().onAuthStateChanged((user) => {
    if (user) {
      const chatId = new URLSearchParams(window.location.search).get("chatId");
      if (!chatId) {
        console.error("Недействительный или отсутствующий chatId в URL.");
        return;
      }

      // Извлечение сообщений в порядке по временной метке
      const messagesRefForDisplay = firebase
        .database()
        .ref(`chats/${chatId}/messages`)
        .orderByChild("timestamp");
      // Используйте обычную ссылку для отправки сообщений
      const messagesRefForSending = firebase
        .database()
        .ref(`chats/${chatId}/messages`);

      // Функция для получения имени пользователя по ID пользователя
      function getUsername(userId, callback) {
        const userRef = firebase.database().ref(`users/${userId}`);
        userRef.once("value", (snapshot) => {
          const userData = snapshot.val();
          callback(userData.username);
        });
      }
      function formatTimestamp(timestamp) {
        const date = new Date(timestamp);
        return date.toLocaleString(); // Настройте формат при необходимости
      }

      // Загружаем сообщения в порядке по временной метке
      messagesRefForDisplay.on("child_added", (snapshot) => {
        const message = snapshot.val();
        getUsername(message.senderId, (username) => {
          const messageElement = document.createElement("div");
          messageElement.classList.add("message");
          const formattedTimestamp = formatTimestamp(message.timestamp);

          messageElement.innerHTML = `<span class="sender">${username}:</span> ${message.message} <span class="timestamp">(${formattedTimestamp})</span>`;
          document.getElementById("messages").appendChild(messageElement);

          // Автопрокрутка вниз после добавления нового сообщения
          document.getElementById("messages").scrollTop =
            document.getElementById("messages").scrollHeight;
        });
      });

      // Отправка сообщения
      document.getElementById("sendMessage").addEventListener("click", () => {
        const messageInput = document.getElementById("messageInput");
        const messageText = messageInput.value.trim();
        if (messageText) {
          // Используйте необработанную ссылку messagesRef для отправки
          messagesRefForSending
            .push({
              message: messageText,
              senderId: user.uid, // Используйте user.uid здесь
              timestamp: Date.now(),
            })
            .then(() => {
              console.log("Сообщение успешно отправлено");
            })
            .catch((error) => {
              console.error("Ошибка при отправке сообщения:", error);
            });
          messageInput.value = ""; // Очистить поле ввода
        }
      });
    } else {
      console.log("Пользователь не вошёл в систему.");
    }
  });
});

Ответ или решение

Для решения проблемы с неправильным порядком сообщений в Firebase, нужно обратить внимание на процесс, который мы используем для отображения сообщений. В вашем текущем коде вы добавляете сообщения в порядок, определяемый Firebase, который может не всегда совпадать с временными метками, особенно если сообщения приходят в разное время.

Проблема

Сообщения выводятся на экран по мере их добавления, и это может привести к неправильному порядку, как в вашем примере. Чтобы исправить это, нужно сначала собрать все сообщения, отсортировать их по временной метке и только затем отобразить.

Решение

Предлагаю следующий алгоритм:

  1. Получите все сообщения из Firebase с сортировкой по временной метке используя once("value") вместо on("child_added"). Это позволит вам получить все сообщения сразу.
  2. Сохраните их в массив.
  3. Отсортируйте массив по временной метке.
  4. После сортировки отобразите сообщения на экране.

Модификация вашего кода

Вот как можно изменить ваш код:

document.addEventListener("DOMContentLoaded", () => {
  firebase.auth().onAuthStateChanged((user) => {
    if (user) {
      const chatId = new URLSearchParams(window.location.search).get("chatId");
      if (!chatId) {
        console.error("Неверный или отсутствующий chatId в URL.");
        return;
      }

      // Ссылка на сообщения
      const messagesRef = firebase.database().ref(`chats/${chatId}/messages`);

      // Функция для получения имени пользователя
      function getUsername(userId, callback) {
        const userRef = firebase.database().ref(`users/${userId}`);
        userRef.once("value", (snapshot) => {
          const userData = snapshot.val();
          callback(userData.username);
        });
      }

      function formatTimestamp(timestamp) {
        const date = new Date(timestamp);
        return date.toLocaleString(); // Можно настроить формат
      }

      // Получение сообщений, сортировка и отображение
      messagesRef.once("value", (snapshot) => {
        const messages = [];
        snapshot.forEach((childSnapshot) => {
          const message = childSnapshot.val();
          messages.push({
            ...message,
            key: childSnapshot.key  // Сохраняем ключ сообщения для дальнейшего использования, если потребуется
          });
        });

        // Сортируем сообщения по временной метке
        messages.sort((a, b) => a.timestamp - b.timestamp);

        // Отображаем сообщения
        messages.forEach((message) => {
          getUsername(message.senderId, (username) => {
            const messageElement = document.createElement("div");
            messageElement.classList.add("message");
            const formattedTimestamp = formatTimestamp(message.timestamp);

            messageElement.innerHTML = `<span class="sender">${username}:</span> ${message.message} <span class="timestamp">(${formattedTimestamp})</span>`;
            document.getElementById("messages").appendChild(messageElement);
          });
        });

        // Автоскроллинг вниз после загрузки всех сообщений
        document.getElementById("messages").scrollTop =
          document.getElementById("messages").scrollHeight;
      });

      // Отправка сообщения
      document.getElementById("sendMessage").addEventListener("click", () => {
        const messageInput = document.getElementById("messageInput");
        const messageText = messageInput.value.trim();
        if (messageText) {
          messagesRef.push({
            message: messageText,
            senderId: user.uid,
            timestamp: Date.now(),
          })
          .then(() => {
            console.log("Сообщение успешно отправлено");
            messageInput.value = ""; // Очистить ввод
          })
          .catch((error) => {
            console.error("Ошибка при отправке сообщения:", error);
          });
        }
      });
    } else {
      console.log("Пользователь не авторизован.");
    }
  });
});

Объяснение изменений:

  1. Получение всех сообщений: Использование once("value") вместо on("child_added") собирает все сообщения сразу.
  2. Сортировка сообщений: После получения всех сообщений мы сортируем массив сообщений по временной метке.
  3. Отображение сообщений: После сортировки сообщения отображаются в верном порядке.
  4. Автоскроллинг: После отображения всех сообщений добавляется автоскроллинг вниз.

Эти изменения должны исправить проблему с порядком сообщений в вашем приложении. Надеюсь, это поможет! Если у вас есть другие вопросы, не стесняйтесь спрашивать.

Оцените материал
Добавить комментарий

Капча загружается...