Skip to content
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

[NDD-240] settingpage 라우터 처리 (1h/2h) #98

Merged
merged 6 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Modal from '../../foundation/Modal';
import Modal from '../../../foundation/Modal';
import { css } from '@emotion/react';
import { theme } from '@/styles/theme';
import Typography from '../../foundation/Typography/Typography';
import Typography from '../../../foundation/Typography/Typography';
import useQuestionAnswerQuery from '@/hooks/queries/useQuestionAnswerQuery';
import AnswerScript from './AnswerScript';
import AnswerForm from './AnswerForm';
Expand Down
21 changes: 0 additions & 21 deletions FE/src/components/interviewSettingPage/VideoSettingBox.tsx

This file was deleted.

43 changes: 25 additions & 18 deletions FE/src/hooks/useMedia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,44 @@ import { useState, useEffect, useCallback, useRef } from 'react';
const useMedia = () => {
const [media, setMedia] = useState<MediaStream | null>(null);
const [selectedMimeType, setSelectedMimeType] = useState('');
const [connectStatus, setIsConnectedStatus] = useState<
const [connectStatus, setConnectStatus] = useState<
'connect' | 'fail' | 'pending'
>('pending');
const videoRef = useRef<HTMLVideoElement>(null);

const connectMedia = useCallback(async () => {
const startMedia = useCallback(async () => {
try {
const media = await getMedia();

setMedia(media);
if (media) setIsConnectedStatus('connect');
else setIsConnectedStatus('fail');
if (videoRef.current) videoRef.current.srcObject = media;
const newMedia = await getMedia();
setMedia(newMedia);
setConnectStatus(newMedia ? 'connect' : 'fail');
if (videoRef.current) videoRef.current.srcObject = newMedia;
} catch (e) {
console.log(`현재 마이크와 카메라가 연결되지 않았습니다`);
console.error('현재 마이크와 카메라가 연결되지 않았습니다.');
setConnectStatus('fail');
}
}, []);

useEffect(() => {
if (!media) {
void connectMedia();
const stopMedia = useCallback(() => {
if (media) {
closeMedia(media);
setMedia(null);
setConnectStatus('pending');
}
}, [media]);

useEffect(() => {
const mimeTypes = getSupportedMimeTypes();
if (mimeTypes.length > 0) setSelectedMimeType(mimeTypes[0]);
}, []);

return () => {
closeMedia(media);
};
}, [media, connectMedia]);

return { media, videoRef, connectStatus, selectedMimeType };
return {
media,
videoRef,
connectStatus,
selectedMimeType,
startMedia,
stopMedia,
};
};

export default useMedia;
10 changes: 3 additions & 7 deletions FE/src/page/interviewSettingPage/QuestionSettingPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { questionSetting } from '@/atoms/interviewSetting';
import Button from '@/components/foundation/Button/Button';
import Description from '@/components/interviewSettingPage/Description';
import QuestionSelectionBox from '@/components/interviewSettingPage/QuestionSelectionBox/QuestionSelectionBox';
import QuestionSelectionBox from '@/components/interviewSettingPage/QuestionPage/QuestionSelectionBox/QuestionSelectionBox';
import { css } from '@emotion/react';
import { useRecoilValue } from 'recoil';

Expand All @@ -17,11 +17,7 @@ const QuestionSettingPage: React.FC<QuestionSettingPageProps> = ({
const setting = useRecoilValue(questionSetting);

return (
<div
css={css`
padding-top: 3rem;
`}
>
<>
<Description title="문제 선택">
- 주어진 카테고리 중에서 관련 있는 문제를 선택해 주세요.
<br />
Expand Down Expand Up @@ -68,7 +64,7 @@ const QuestionSettingPage: React.FC<QuestionSettingPageProps> = ({
다음
</Button>
</div>
</div>
</>
);
};

Expand Down
8 changes: 2 additions & 6 deletions FE/src/page/interviewSettingPage/RecordSettingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,7 @@ const RecordSettingPage: React.FC<RecordSettingPageProps> = ({
};

return (
<div
css={css`
padding-top: 3rem;
`}
>
<>
<Description title="녹화 설정">
- 면접 시작 전, 사용하시는 장치의 화면 및 소리가 정상적으로 연결되어
있는지 확인해 주세요.
Expand Down Expand Up @@ -111,7 +107,7 @@ const RecordSettingPage: React.FC<RecordSettingPageProps> = ({
다음
</Button>
</div>
</div>
</>
);
};
export default RecordSettingPage;
25 changes: 18 additions & 7 deletions FE/src/page/interviewSettingPage/VideoSettingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,31 @@ import { useRecoilState } from 'recoil';
type VideoSettingPageProps = {
onNextClick?: () => void;
onPrevClick?: () => void;
isCurrentPage: boolean;
};

const VideoSettingPage: React.FC<VideoSettingPageProps> = ({
onNextClick,
onPrevClick,
isCurrentPage,
}) => {
const [videoSettingState, setVideoSettingState] =
useRecoilState(videoSetting);

const { videoRef: mirrorVideoRef, connectStatus } = useMedia();
const {
videoRef: mirrorVideoRef,
connectStatus,
startMedia,
stopMedia,
} = useMedia();

useEffect(() => {
if (isCurrentPage) void startMedia();

return () => {
stopMedia();
};
}, [isCurrentPage]);

useEffect(() => {
if (connectStatus === 'connect') {
Expand All @@ -35,11 +50,7 @@ const VideoSettingPage: React.FC<VideoSettingPageProps> = ({
}, [connectStatus, setVideoSettingState]);

return (
<div
css={css`
padding-top: 3rem;
`}
>
<>
<Description title="문제 선택">
- 면접 시작 전, 사용하시는 장치의 화면 및 소리가 정상적으로 연결되어
있는지 확인해 주세요.
Expand Down Expand Up @@ -111,7 +122,7 @@ const VideoSettingPage: React.FC<VideoSettingPageProps> = ({
다음
</Button>
</div>
</div>
</>
);
};

Expand Down
28 changes: 23 additions & 5 deletions FE/src/page/interviewSettingPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,15 @@ import { css } from '@emotion/react';
import RecordSettingPage from './RecordSettingPage';
import VideoSettingPage from './VideoSettingPage';

const FIRST_PAGE_INDEX = 0;
const PREV_PAGE_INDEX = -1;

const InterviewSettingPage: React.FC = () => {
const navigate = useNavigate();
const [searchParams, setSearchParams] = useSearchParams();

const currentPage = searchParams.get('page');

const pageInfo = [
{
name: '문제 선택',
Expand All @@ -33,6 +40,7 @@ const InterviewSettingPage: React.FC = () => {
path: SETTING_PATH.CONNECTION,
page: (
<VideoSettingPage
isCurrentPage={currentPage === SETTING_PATH.CONNECTION}
onPrevClick={() => changeSearchParams(SETTING_PATH.QUESTION)}
onNextClick={() => changeSearchParams(SETTING_PATH.RECORD)}
/>
Expand All @@ -51,9 +59,8 @@ const InterviewSettingPage: React.FC = () => {
state: useRecoilValue(recordSetting),
},
];
const validPagePaths = pageInfo.map((item) => item.path);

const [searchParams, setSearchParams] = useSearchParams();
const currentIndex = pageInfo.findIndex((item) => item.path === currentPage);

const changeSearchParams = (newPage: string) => {
const newSearchParams = new URLSearchParams(searchParams);
Expand All @@ -62,12 +69,23 @@ const InterviewSettingPage: React.FC = () => {
};
// TODO: 로직이 더 길어지면 hook으로 분리해도 나쁘지 않을듯

const currentPage = searchParams.get('page');

if (!currentPage || !validPagePaths.includes(currentPage)) {
const isValidatePath = currentIndex !== -1;
if (!isValidatePath) {
return <Navigate to={`?page=${SETTING_PATH.QUESTION}`} replace />;
}

const prevPageInfo =
currentIndex === FIRST_PAGE_INDEX
? pageInfo[FIRST_PAGE_INDEX]
: pageInfo[currentIndex + PREV_PAGE_INDEX];

const isValidatePrevPageStatus =
currentIndex !== FIRST_PAGE_INDEX && !prevPageInfo.state.isSuccess;

if (isValidatePrevPageStatus) {
return <Navigate to={`?page=${prevPageInfo.path}`} replace />;
}

return (
<InterviewSettingPageLayout>
<div
Expand Down
Loading