ChatParticipants.tsx 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. 'use client';
  2. import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
  3. import { faXmark, faUser } from '@fortawesome/free-solid-svg-icons';
  4. import type { ChatParticipant } from '@/types/chat';
  5. type Props = {
  6. participants: ChatParticipant[];
  7. loading: boolean;
  8. onClose: () => void;
  9. };
  10. // 접속 참여자 목록 — 채팅 본체(.chat-room__body) 위에 오버레이. row: ICON·별명·SID·LEVEL(등급 Order)
  11. export default function ChatParticipants({ participants, loading, onClose }: Props)
  12. {
  13. return (
  14. <div className='chat-participants' role='dialog' aria-label='접속 참여자 목록'>
  15. <div className='chat-participants__head'>
  16. <span className='chat-participants__title'>접속자 {participants.length.toLocaleString()}명</span>
  17. <button type='button' className='chat-participants__close' onClick={onClose} aria-label='목록 닫기' title='목록 닫기'>
  18. <FontAwesomeIcon icon={faXmark} />
  19. </button>
  20. </div>
  21. <div className='chat-participants__body'>
  22. {loading ? (
  23. <div className='chat-participants__empty'>불러오는 중…</div>
  24. ) : participants.length === 0 ? (
  25. <div className='chat-participants__empty'>접속 중인 회원이 없습니다.</div>
  26. ) : (
  27. <ul className='chat-participants__list'>
  28. {participants.map((p, idx) => (
  29. <li key={p.sid ?? `${p.memberName}-${idx}`} className='chat-participants__item'>
  30. <span className='chat-participants__avatar'>
  31. {p.icon ? (
  32. // eslint-disable-next-line @next/next/no-img-element
  33. <img src={p.icon} alt='' aria-hidden='true' />
  34. ) : (
  35. <FontAwesomeIcon icon={faUser} />
  36. )}
  37. </span>
  38. <span className='chat-participants__info'>
  39. <span className='chat-participants__name'>{p.memberName}</span>
  40. {p.sid && <span className='chat-participants__sid'>@{p.sid}</span>}
  41. </span>
  42. <span className='chat-participants__level' title='회원 등급'>Lv.{p.level}</span>
  43. </li>
  44. ))}
  45. </ul>
  46. )}
  47. </div>
  48. </div>
  49. );
  50. }