-
Notifications
You must be signed in to change notification settings - Fork 1
[FE] 입장 준비 화면 UI 구현 #168
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[FE] 입장 준비 화면 UI 구현 #168
Conversation
- 미참여시 로비 컴포넌트 렌더 - 참여확정 시 미팅룸 컴포넌트 렌더
- 미디어스트림 생성 및 연결 - 카메라 및 오디오 연결 로직 추가
- 미디어 프리뷰 UI 구현 및 훅 활용 - 미팅 로비 UI 레이아웃 세팅
- 빈 라벨 필터링 로직 추가 - 스피커, 마이크, 카메라 기기 리스트 페칭
- 기기와 아이콘 등 props 설정 - 비활성화 스타일 추가 - Lobby에서 컴포넌트 레이아웃 호출 등
- 각 스트림별로 권한 여부를 관리하기 위해 로직 추가 - 스트림별 상태에 따른 아이콘 조건부 스타일링 로직 추가
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
일단 역할 분리가 굉장히 잘 되어있다는 느낌을 받았습니다. 고생하셨습니다.!!
질문은 아래 코멘트로 남겼습니다!!
| const toggleVideo = useCallback(() => { | ||
| streamRef.current?.getVideoTracks().forEach((track) => { | ||
| track.enabled = !track.enabled; | ||
| setMedia((prev) => ({ ...prev, videoOn: track.enabled })); | ||
| }); | ||
| }, []); | ||
|
|
||
| const toggleAudio = useCallback(() => { | ||
| streamRef.current?.getAudioTracks().forEach((track) => { | ||
| track.enabled = !track.enabled; | ||
| setMedia((prev) => ({ ...prev, audioOn: track.enabled })); | ||
| }); | ||
| }, []); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
p4: 카메라를 비활성화했음에도 브라우저에서는 계속 사용 중으로 떠 찾아보니 track.enabled = false로는 실제 디바이스 사용 중단까지는 가지 않는다고 해요 완전히 사용을 종료하려면 track.stop()을 사용해야하는데
줌이나 구글 미트에서는 카메라 차단시 완전히 꺼졌던거같아서
카메라 또는 마이크가 완전히 종료되지 않는 동작을 의도하신건지 궁금합니다. (빠른 토글 같은 장점?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아하 카메라 불빛까지는 신경을 못 썼던 것 같아요! 놓친 부분이었는데 감사합니다 ~!
seorang42
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
잘 작동하는 것 확인했습니다!
고생 많으셨어요!!
| base: 'inline-flex items-center justify-center box-border select-none m-0 p-0 w-fit h-fit cursor-pointer disabled:cursor-default', | ||
| size: { | ||
| sm: 'h-full max-h-[50px] px-3 py-[6px] text-sm font-bold', | ||
| sm: 'h-full h-auto px-3 py-[6px] text-sm font-bold', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
px-[6px]로 작성하면 혹시 VSCODE에서
The class `px-[6px]` can be written as `px-1.5`(suggestCanonicalClasses)
이런 Warning 밑줄 안생기나요??
저도 저렇게 했었다가 최근 Tailwind에선 저렇게 경고가 생겨서 .5나 .25 등의 기능을 사용하는 편이라 질문 드려요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
className에서 쓸 땐 warning이 뜨는데 style 정의로 작성했다보니 안 뜬 것 같아요! 놓친 부분이었는데 감사합니다~
| {!isJoined ? ( | ||
| <MeetingLobby meetingId={meetingId} onJoin={handleJoin} /> | ||
| ) : ( | ||
| <MeetingRoom meetingId={meetingId} /> | ||
| )} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
제 PR에 리뷰를 남겨주셨던 부분이 이 부분이었나보네요!
참여 준비 화면과 실제 화상 회의 페이지를 하나로 만드는게 좋을까요?
아니면 별도의 페이지로 분리하는게 좋을까요?
일단 구글 meet에서는 구현해주신대로
새로고침 시 검증 및 준비를 다시 요청하는 방식으로 진행되고 있기는 하네요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저도 하나의 페이지에서 핸들하는 게 좋을지, 별도의 페이지로 분리하는 게 좋을지 고민이 되었는데 구글미트를 참고해 우선 진행했어요. 그리고 AI에게 피드백을 받아봤는데 아래와 같은 관점으로 봐도 좋을 것 같아요!
Next.js 관점
- 사용자 경험 (Seamless UX): 사용자가 '참여하기'를 눌렀을 때 페이지 전체가 새로고침되지 않고, 필요한 컴포넌트(회의창)만 즉시 로드되게 한다.
- 데이터 무결성:
meetingId라는 동일한 컨텍스트 안에서 상태가 유지되므로, 로비에서 설정한 오디오/비디오 스트림 객체를 회의실 컴포넌트로 그대로 넘겨주기 쉽다. - URL 간결화: 구글 미트처럼 단일 URL(
.../meeting/abc-def)을 유지하면서도 내부 로직만으로 흐름을 완벽히 제어할 수 있다.
추가 포인트
만약 로그인하지 않은 사용자를 /landing으로 보내야 한다면, page.tsx 상단이나 Next.js Middleware에서 체크하는 것이 좋다.
// middleware.ts 예시
if (!session && request.nextUrl.pathname.startsWith('/meeting')) {
return NextResponse.redirect(new URL('/landing', request.url));
}⇒ 일단 우리 서비스에선 비로그인 사용자도 참여 가능하다. → 비회원인 경우 넘어갈 페이지로 미들웨어 설정해주기?
| <CamOffIcon className="h-12 w-12 rounded-full bg-white p-4 text-neutral-700 shadow-lg" /> | ||
| </button> | ||
|
|
||
| <button onClick={toggleAudio}> | ||
| <MicOffIcon className="h-12 w-12 rounded-full bg-white p-4 text-neutral-700 shadow-lg" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: 영상 내부의 아이콘에 p-4가 적용되어 있어서 아이콘의 크기가 의도한 것보다 더 작아진 것 같아요
p-3으로 수정 부탁드려요!
| button { | ||
| cursor: pointer; | ||
| } | ||
|
|
||
| button:disabled { | ||
| cursor: not-allowed; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P4: 두 개를 Tailwind로 합쳐서
button { @apply cursor-pointer disabled:cursor-not-allowed } 로 정의할 수도 있을 것 같네요
| </button> | ||
|
|
||
| {!isDisabled && isOpen && ( | ||
| <ul className="absolute z-10 mt-1 w-full rounded-sm border border-neutral-400 bg-white shadow"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P3: shadow가 있어서 border가 조금 연해도 보기 불편하지 않을 것 같아요!
적용해봤을 때 neutral-200이 가장 적당했던 것 같습니다!
P5: 직접 사용해보니까 장치가 많아졌을 때 드롭다운의 높이가 높아져서 전체 페이지가 스크롤되게 되더라고요
드롭다운의 높이를 고정값으로 설정하고 스크롤 방식으로 목록을 표시하는 것도 괜찮을 것 같다고 생각했습니다!
| <Icon className="h-4 w-4 shrink-0" /> | ||
| <span className="truncate">{selected?.label || `접근 권한 필요`}</span> | ||
|
|
||
| <span className="flex-1 text-right">▾</span> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: assets/icons/common/arrowDownIcon.svg에 여기서 사용될 아이콘도 저장되어 있어요!
추가적으로 이 부분이 텍스트가 길어졌을 때 flex로 인해 찌그러지더라고요
위의 아이콘처럼 shrink-0 설정해주시면 좋을 것 같아요!
- ArrowDownIcon 적용 - 테일윈드 클래스 사용 지향 등
실제 디바이스 사용 중단까지 도달하도록 track.stop() 적용
🎯 이슈 번호
✅ 작업 내용
미팅 로비(Lobby) UI 구현
useMediaPreview 훅 구현
useMediaDevices 훅 구현
전체 흐름
구글 미트의 회의 흐름을 참고하여 하나의 미팅페이지에서 컴포넌트가 교체되도록 작업하였습니다.
시나리오는 아래와 같습니다.
개념 정리
🤔 리뷰 요구사항
메모
📸 스크린샷 (선택)
-- 01.07 updated --


