[chat] 귓속말 기능

miin·2022년 6월 13일
0

Skill Collection [Function]

목록 보기
34/44

결과

내용

  • 왼쪽의 플러스 버튼 클릭시 모달창이 뜨고, 귓속말 select에서 유저를 선택할 수 있다
  • 내용 입력 후 보내면 내가 보낸 창은 오른쪽에, 받는 채팅은 왼쪽에 출력
  • {보내는사람}님에게 귓속말을 보냈습니다. {받는사람}님이 귓속말을 보냈습니다.
  • 귓속말 모드일때 placeholder로 현재 귓속말 모드이고, 종료 방법을 알려줌
  • esc로 귓속말 모드를 종료할 수 있다
  • 귓속말 모드일땐 상대방에게 타이핑 여부를 알리지 않는다

코드

client

나를 제외한 유저만 담기

<select onChange={handleWhisper}>
                    <option value="" >
                      귓속말
                    </option>
                    {userList
                      .filter((me) => me !== user?.nick)
                      .map((user) => (
                        <option key={user.member_no} value={user}>
                          {user}
                        </option>
                      ))}
  </select>

귓속말 대상 유저 state에 반영하기

  const handleWhisper = (e) => {
    setWhisperUser(e.target.value);
  };

서버로 보내기

const handleSend = () => {
    if (message) {
      if (message.length === 0) {
        alert("채팅 내용을 입력해주세요.");
        return;
      }

      //whisperUser가 있으면 type이"SEND_WHISPER"고, whisperUser를 보냄
      //whisperUser가 없으면 일반 메세지로 type이 "USER_TEXT"로 보냄
      if (whisperUser) {
        socket.emit("/rooms/message", {
          chat: message,
          roomNo: props.roomNo,
          memberNo: user?.member_no,
          nick: user?.nick,
          type: "SEND_WHISPER",
          whisperUser: whisperUser,
        });
      } else {
        //메세지 서버로 보냄
        socket.emit("/rooms/message", {
          chat: message,
          roomNo: props.roomNo,
          memberNo: user?.member_no,
          nick: user?.nick,
          type: "USER_TEXT",
        });
      }
      setIsTyping(false);
      setMessage("");
    }
  };

서버에서 받기

      socket.on("send whisperUser", (data) => {

        // 서버에서 받아온 memberNo와 현재 user의 member_no가 같고 
        // 서버에서 받아온 type이 "SEND_WHISPER"인 데이터는 isMyMessage: true
        // isMyMessage이면 오른쪽 정렬이 됨 
        const notice = {
          ...data,
          isMyMessage:
            data.memberNo === user?.member_no && data?.type === "SEND_WHISPER",
        };

        setMessages((messages) => [...messages, notice]);
      });

return

	//isMyMessage가 true이고 type이 "SEND_WHISPER"이면
	// 오른쪽 정렬, {보내는사람}님에게 귓속말을 보냈습니다
	//isMyMessage가 false이고 type이 "SEND_WHISPER"이면
	// 왼쪽 정렬, {받는사람}님에게 귓속말을 받았습니다
	// 둘다 아니면 일반채팅
		<div className="talk_chatList">
            {isMyMessage && type === "SEND_WHISPER"
              ? `${whisperUser}님에게 귓속말을 보냈습니다. : ${chat}`
              : !isMyMessage && type === "SEND_WHISPER"
              ? `${nick}님이 귓속말을 보냈습니다. : ${chat}`
              : chat}
		</div>

귓속말 모드 알려주기

  const handleEnterOnMessage = (e) => {
    if (e.key === "Enter") {
      handleSend();
    }
    if (e.key === "Escape") {
      setWhisperUser("");
    }
  };

return(
          <input
            className="chatInput"
            placeholder={
              whisperUser
                ? `${whisperUser}님에게 귓속말: * 귓속말 종료시 esc를 누르세요.`
                : "Write a message.."
            }
            onChange={handleMessage}
            onKeyUp={handleEnterOnMessage}
            value={message}
          />
)

귓속말 모드일땐 상대방에게 타이핑 여부를 알리지 않는다

  const handleMessage = (e) => {
    e.preventDefault();
    setIsTyping(true);
    setMessage(e.target.value);

    if (!whisperUser) {
      socket.emit("/rooms/typing", {
        roomNo: props.roomNo,
        ...user,
        isTyping,
        type: "SYSTEM_USER_TYPING",
      });
    }
  };

전체코드

//귓속말 서버에서 받기
      socket.on("send whisperUser", (data) => {
        console.log("귓속말", data);

        const notice = {
          ...data,
          isMyMessage:
            data.memberNo === user?.member_no && data?.type === "SEND_WHISPER",
        };

        setMessages((messages) => [...messages, notice]);
      });

//send가 실행되고 채팅 내용이 db로 추가됨
  const handleSend = () => {
    if (message) {
      if (message.length === 0) {
        alert("채팅 내용을 입력해주세요.");
        return;
      }

      if (whisperUser) {
        console.log("서버로 귓속말 보내기 ", whisperUser);

        // 귓속말
        socket.emit("/rooms/message", {
          chat: message,
          roomNo: props.roomNo,
          memberNo: user?.member_no,
          nick: user?.nick,
          type: "SEND_WHISPER",
          whisperUser: whisperUser,
        });
      } else {
        //메세지 서버로 보냄
        socket.emit("/rooms/message", {
          chat: message,
          roomNo: props.roomNo,
          memberNo: user?.member_no,
          nick: user?.nick,
          type: "USER_TEXT",
        });
      }
      setIsTyping(false);
      setMessage("");
    }
  };

  //귓속말할 user
  const handleWhisper = (e) => {
    setWhisperUser(e.target.value);
  };

return(
    <ul key={key} className={isMyMessage ? "talk_myChatWrap" : "otherMsg"}>
      {!isMyMessage && (
        <div className="imgBox">
          <img alt="profileImg" src="/img/profile.jpeg" />
        </div>
      )}
      <li className={isMyMessage ? "talk_myChatWrap" : "talk_chatWrap"}>
        <div>
          {!isMyMessage && <div className="profileName">{nick}</div>}

          <div className="talk_chatList">
            {isMyMessage && type === "SEND_WHISPER"
              ? `${whisperUser}님에게 귓속말을 보냈습니다. : ${chat}`
              : !isMyMessage && type === "SEND_WHISPER"
              ? `${nick}님이 귓속말을 보냈습니다. : ${chat}`
              : chat}
          </div>
          <div className="time">{time}</div>
        </div>
      </li>
    </ul>

 <button
            className="plusButton"
            onClick={() => {
              setPlusButton(true);
            }}
          ></button>
          {plusButton && (
            <div className="plusBox" ref={modalRef}>
              <ul>
                <li>
                  <select onChange={handleWhisper}>
                    <option value="">귓속말</option>
                    {userList
                      .filter((me) => me !== user?.nick)
                      .map((user) => (
                        <option key={user.member_no} value={user}>
                          {user}
                        </option>
                      ))}
                  </select>
                </li>
                <li>
                  <label className="imgPlusLabel">
                    앨범
                    <input
                      className="imgPlus"
                      id="img"
                      type="file"
                      accept="image/*"
                    />
                  </label>
                </li>
                <li>
                  <label className="filePlusLabel">
                    파일
                    <input className="filePlus" id="file" type="file" />
                  </label>
                </li>
              </ul>
            </div>
          )}

          <input
            className="chatInput"
            placeholder={
              whisperUser ? `${whisperUser}님에게 귓속말:` : "Write a message.."
            }
            onChange={handleMessage}
            onKeyUp={handleEnterOnMessage}
            value={message}
          />
          <button className="sendButton" onClick={handleSend}>
            Send
          </button>
        </div>
  );

server

  socket.on("/rooms/message", (data) => {
    const { roomNo, type, whisperUser, nick } = data;

    if (type === "USER_TEXT") //일반채팅
      sql = `INSERT INTO chat(member_no, room_no, chat, sended) VALUES (:memberNo, :roomNo, :chat, now())`;
    else //귓속말 채팅
      sql = `INSERT INTO chat(member_no, room_no, chat, sended, type, whisper_user) VALUES (:memberNo, :roomNo, :chat, now(), :type, :whisperUser)`;

    _db.qry(sql, data).then(() => {
      //일반채팅
      if (type === "USER_TEXT") io.in(roomNo).emit("/rooms/message", { data });
      //귓속말 채팅
      else
        io.to(nick).to(whisperUser).in(roomNo).emit("send whisperUser", data);
    });
  });

0개의 댓글