Vue3, Firebase 프로젝트 - 채팅앱 VSignal

15. Vue3 Firebase 프로젝트 채팅앱 VSignal - 안 읽은 메시지 있는 채팅방 상단에 정렬 하기

그랜파 개발자 2025. 3. 26. 05:52

🔥 안 읽은 메시지가 있는 채팅방을 상단으로 정렬하기

안 읽은 메시지가 많은 채팅방을 상단으로 정렬하면
채팅방이 아래에 있는 경우 메시지가 있는지 여부를 확인하지 못하여
오랫동안 메시지를 읽지 않고 방치하는 것을 방지할 수 있습니다.

1. Store에서 채팅방 정렬 로직 추가

📌 store/chatStore.js 수정

import { defineStore } from "pinia";
import { getDatabase, ref, onValue } from "firebase/database";
import { auth } from "@/firebase";

export const useChatStore = defineStore("chat", {
  state: () => ({
    chatRooms: [], // 채팅방 목록
    unreadCounts: {}, // 채팅방별 안 읽은 메시지 개수
  }),

  actions: {
    // ✅ 채팅방 목록 가져오기
    fetchChatRooms() {
      const db = getDatabase();
      const user = auth.currentUser;
      if (!user) return;

      const chatRoomsRef = ref(db, `users/${user.uid}/chatRooms`);
      onValue(chatRoomsRef, (snapshot) => {
        if (snapshot.exists()) {
          this.chatRooms = Object.entries(snapshot.val()).map(([id, room]) => ({
            id,
            ...room,
          }));
          this.listenForUnreadMessages();
        }
      });
    },

    // ✅ 안 읽은 메시지 개수 업데이트
    listenForUnreadMessages() {
      const db = getDatabase();
      const user = auth.currentUser;
      if (!user) return;

      this.chatRooms.forEach((room) => {
        const messagesRef = ref(db, `messages/${room.id}`);

        onValue(messagesRef, (snapshot) => {
          if (snapshot.exists()) {
            const unreadMessages = Object.values(snapshot.val()).filter(
              (msg) => msg.receiver === user.uid && msg.status === "unread"
            );
            this.unreadCounts[room.id] = unreadMessages.length;
          } else {
            this.unreadCounts[room.id] = 0;
          }
        });
      });
    },
  },

  getters: {
    // ✅ 채팅방을 안 읽은 메시지가 많은 순서로 정렬
    sortedChatRooms: (state) => {
      return [...state.chatRooms].sort((a, b) => {
        const unreadA = state.unreadCounts[a.id] || 0;
        const unreadB = state.unreadCounts[b.id] || 0;
        return unreadB - unreadA; // 안 읽은 메시지가 많은 순으로 정렬
      });
    },
  },
});

✔ sortedChatRooms 안 읽은 메시지 개수를 기준으로 정렬
✔ 안 읽은 메시지가 많을수록 상단에 배치

2. UI에서 정렬된 채팅방 표시

📌 ChatList.vue 수정

<script setup>
import { useChatStore } from "@/store/chatStore";
import { onMounted } from "vue";

const chatStore = useChatStore();

onMounted(() => {
  chatStore.fetchChatRooms();
});
</script>

<template>
  <v-list>
    <v-list-item
      v-for="chatRoom in chatStore.sortedChatRooms"
      :key="chatRoom.id"
      :to="`/chat/${chatRoom.id}`"
    >
      <v-list-item-content>
        <v-list-item-title>{{ chatRoom.name }}</v-list-item-title>
      </v-list-item-content>

      <!-- ✅ 안 읽은 메시지가 있으면 배지 표시 -->
      <v-badge
        v-if="chatStore.unreadCounts[chatRoom.id] > 0"
        :content="chatStore.unreadCounts[chatRoom.id]"
        color="red"
      >
        <v-icon>mdi-message</v-icon>
      </v-badge>
    </v-list-item>
  </v-list>
</template>

✔ 정렬된 채팅방 목록을 sortedChatRooms로 렌더링
✔ 안 읽은 메시지가 많은 채팅방이 자동으로 상단에 배치

🎯 결론

✅ 채팅방을 안 읽은 메시지 개수를 기준으로 정렬
✅ 안 읽은 메시지가 많을수록 상단에 배치
✅ 새 메시지가 오면 자동으로 정렬 업데이트 🚀