project/모임웹프로젝트

모임 웹프로젝트 실시간 채팅 프런트 구성

naspeciallist 2024. 11. 19. 11:34

 

메인페이지에서 맞춤형 상대 찾기 메뉴를 클릭하게 하면 맞춤형 상대 찾기 페이지로 이동 할 수 있게 구성을 하였습니다. 

관심사를 기준으로 공통된 관심사가 있는 상대를 고른 후 무작위로 한명을 선택하여 매칭이 될 수 있게 하도록 했습니다.

 

맞춤형 상대 찾기 페이지 입니다.

상단에 어플리케이션을 이용중인 유저의 관심사를 버튼형식으로 띄운 뒤 그 밑에 채팅방을 구성하였습니다.

 

채팅방 하단에는 상대의 프로필을 확인 할 수 있게 하였고 다중 프로필을 이용하는 사용자일 경우 스크롤 버튼을 통해 여러장의 프로필을 모두 조회 할 수 있게 구성을 하였습니다.

 

이름 나이 자기소개 항목을 가져와서 카드형식으로 보일 수 있게 하였고 다른 상대 찾기 버튼과 좋아요 누르고 채팅방 저장하기 버튼을 추가하였습니다.

 

다른상대 찾기 버튼을 클릭시 채팅방 내용을 저장 하지 않고 다른 상대로 이동 할 수 있게 구성을 하였고 좋아요 누르고 채팅방 저장하기 버튼을 클릭시 상대 좋아요를 한 뒤 나눈 대화를 저장하여 마이페이지를 통해 불러 올 수 있게 하였습니다.

 

맞춤형 상대 찾기 페이지는 메인페이지와 마친가지로 타임리프를 이용하여 fragments로 구성을 하였습니다.

 

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>메인페이지</title>
    <!-- 부트스트랩 cdn -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <!-- 부트스트랩 아이콘 cdn -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css" rel="stylesheet">
    <link th:href="@{/css/basic.css}" rel="stylesheet">
    <link th:href="@{/css/chatroomStyle.css}" rel="stylesheet">
<!--    웹소켓 라이브러리-->
    <script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/stompjs@2.3.3/lib/stomp.min.js"></script>

</head>
<body>
<!-- 헤더 영역 -->
<th:block th:replace="fragments/nav :: header"></th:block>

<!-- 메인 컨텐츠 영역 -->
<th:block th:replace="fragments/chatroomContent"></th:block>

<!-- 푸터 영역 -->
<th:block th:replace="fragments/nav :: footer"></th:block>


<script th:src="@{/js/chatroom.js}"></script>

</body>
</html>

 

실시간 상대찾기 페이지의 컨텐츠 영역의 코드입니다.

<div class="container">
  <!-- 관심사 태그 -->
  <div class="interests" th:if="${user != null and user.interests != null}">
    <div th:each="interest : ${user.interests}" class="interest-tags">
      <button class="interest-tag" th:text="'#' + ${interest.interestName}"></button>
    </div>
  </div>


  <div class="chat-box">
    <div id="chatRoom" th:attr="data-room-id=${roomId}, data-other-user-id=${otherUserId}, data-user-id=${username}">

    </div>


    <div class="chat-input">
      <input type="text" id="messageInput" placeholder="메시지를 입력하세요">
      <button id="sendBtn" onclick="sendMessage()">전송</button>
    </div>
  </div>

  <!-- 프로필 카드 -->
  <div th:if="${otherUser != null}" class="profile-card">
    <!-- 슬라이드 가능한 프로필 이미지 영역 -->
    <div class="profile-slider">
      <button class="slide-btn prev-btn" onclick="prevImage()">&#10094;</button> <!-- 이전 화살표 -->

      <!-- 프로필 이미지 슬라이드 -->
      <div class="profile-images">
        <img th:each="profileImageUrl, iterStat : ${profileImageUrls}"
             th:src="@{|/files?fileName=${profileImageUrl}|}"
             alt="상대방 프로필 사진"
             class="profile-pic" th:classappend="${iterStat.index == 0} ? 'active' : ''">
      </div>

      <button class="slide-btn next-btn" onclick="nextImage()">&#10095;</button> <!-- 다음 화살표 -->
    </div>

    <!-- 프로필 정보 -->
    <div class="profile-info">
      <h3 th:text="${otherUser.name}">상대방 이름</h3>
      <!-- 주소에서 도시명만 추출하여 표시 -->
      <p id="user-info" th:attr="data-birth-date=${otherUser.birthDate}" th:text="${#strings.arraySplit(otherUser.address, ' ')[0]} + ' | 나이 계산 중...'">상대방 주소 및 정보</p>
      <!-- introduce 내용을 표시 -->
      <p th:text="${otherUser.introduce != null ? otherUser.introduce : '소개 정보가 없습니다.'}">소개</p>
    </div>
  </div>
</div>


  <!-- 하단 액션 버튼 -->
  <div class="actions">
    <button class="find-another"  onclick="findAnotherUser()">다른 상대 찾기</button>
    <button class="like-and-save"  onclick="likeAndSaveChatRoom()" >좋아요 누르고 채팅방 저장하기</button>
  </div>
</div>

 

th 구문을 활용하여 서버 사이드에서 데이터를 HTML로 동적으로 렌더링 하였습니다. 

데이터를 이용하여 상호작용 할 수 있는 요소들을 구성해 보았습니다.
데이터 바인딩을 위해 data-* 속성을 사용 (예: data-room-id, data-birth-date) 하였으며 
JavaScript에서 이 데이터를 읽고 동작 처리에 활용 가능하도록 구성을 하였습니다.

 

스크립트 부분 코드 입니다.

let roomId = document.getElementById('chatRoom').getAttribute('data-room-id');
let otherUserId = document.getElementById('chatRoom').getAttribute('data-other-user-id');
let loggedInUserId = document.getElementById('chatRoom').getAttribute('data-user-id');
let stompClient = null;
let lastSenderId = null;

 

data 속성을 이용하여 보낸 데이터들을 전역변수로 선언을 해 주었습니다.

 

그 뒤 웹소켓 연결을 위한 스크립트 코드를 구성하였습니다.

 

웹소켓 구성 부분은 다음 게시물로 자세하게 설명드리도록 하겠습니다.

 

document.addEventListener('DOMContentLoaded', function() {
    loadChatHistory();  // 이전 채팅 기록 불러오기
    connect();  // WebSocket 연결
});


let currentIndex = 0;
const profilePics = document.querySelectorAll('.profile-pic');

/// 이미지 슬라이드 업데이트 함수
function updateSlide() {
    const profilePics = document.querySelectorAll('.profile-pic');
    profilePics.forEach((pic, index) => {
        pic.classList.toggle('active', index === currentIndex);
    });
}

// 이전 이미지로 이동
function prevImage() {
    currentIndex = (currentIndex - 1 + profilePics.length) % profilePics.length;
    updateSlide();
}

// 다음 이미지로 이동
function nextImage() {
    currentIndex = (currentIndex + 1) % profilePics.length;
    updateSlide();
}

// 초기 슬라이드 설정
document.addEventListener('DOMContentLoaded', updateSlide);


document.addEventListener('DOMContentLoaded', function() {
    const userInfoElement = document.getElementById('user-info');
    const birthDate = new Date(userInfoElement.getAttribute('data-birth-date'));

    if (!isNaN(birthDate)) {
        const today = new Date();
        let age = today.getFullYear() - birthDate.getFullYear();
        const monthDiff = today.getMonth() - birthDate.getMonth();

        // 생일이 지났는지 확인하여 나이 조정
        if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
            age--;
        }

        // 나이를 포함한 텍스트 설정
        const city = userInfoElement.textContent.split(" | ")[0];  // 도시 이름 추출
        userInfoElement.textContent = `${city} | ${age}세`;
    }
});

 

 

 

초기 정보를 업데이트 해주는 스크립트 코드 입니다.

 

위에서 전역변수로 처리한 data를 이용하여 나이를 계산하여 출력 할 수 있도록 도와줍니다.

 

또한 이미지 슬라이더 기능을 추가하여 동적으로 상대방의 프로필을 확인 할 수 있도록 구성을 하였습니다.