Skip to content

Commit 02aac85

Browse files
authored
Merge pull request #161 from boostcampwm-2022/144-interviewdocs-컴포넌트-구현
InterviewDocsList, InterviewDocs 컴포넌트 추가
2 parents a0a9659 + dee84cc commit 02aac85

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+577
-306
lines changed

frontend/src/components/@drawer/RecordDrawer/RecordDrawer.tsx

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,19 @@
1-
import DocsItem from '@components/DocsItem/DocsItem';
2-
import { REST_TYPE } from '@constants/rest.constant';
3-
import { DocsItemDtoType } from '@customType/dto';
4-
import axios from 'axios';
5-
import React, { useEffect, useState } from 'react';
1+
import React from 'react';
62

7-
const initialDocsList = [
8-
{ docsUUID: 'asdf', createdAt: new Date(), playTime: 20000 },
9-
{ docsUUID: 'qwe', createdAt: new Date(), playTime: 454630 },
10-
{ docsUUID: 'zxc', createdAt: new Date(), playTime: 798760 },
11-
{ docsUUID: 'wer', createdAt: new Date(), playTime: 58760 },
12-
];
3+
import DocsItem from '@components/InterviewDocsItem/InterviewDocsItem';
4+
import { docsListQuery } from '@store/interviewDocs.store';
5+
import { roomUUIDState } from '@store/room.store';
6+
7+
import { useRecoilValue } from 'recoil';
138

149
const RecordDrawer = () => {
15-
const [docsList, setDocsList] = useState<DocsItemDtoType[]>(initialDocsList);
16-
// useEffect(() => {
17-
// const fetch = async () => {
18-
// const res = await axios.get(REST_TYPE.INTERVIEW_DOCS_LIST);
19-
// setDocsList(res.data);
20-
// };
21-
// fetch();
22-
// }, []);
10+
const roomUUID = useRecoilValue(roomUUIDState);
11+
const docsList = useRecoilValue(docsListQuery(roomUUID));
2312

2413
return (
2514
<>
2615
{docsList.map((docs, idx) => (
27-
<DocsItem key={docs.docsUUID} docs={docs} idx={idx} style='card' />
16+
<DocsItem key={docs.id} docs={docs} idx={idx} style="card" />
2817
))}
2918
</>
3019
);

frontend/src/components/@drawer/UserDrawer/UserDrawer.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ const UserDrawer = () => {
2222
return (
2323
<>
2424
<div css={userListStyle}>
25+
<div>
26+
<div>{me.nickname}</div>
27+
<div>
28+
<MicOnIcon {...iconSmStyle} />
29+
<CameraOnIcon {...iconSmStyle} />
30+
</div>
31+
</div>
2532
{others.map((other, i) => (
2633
<div key={i}>
2734
<div>{other.nickname}</div>

frontend/src/components/Modal/EnterRoomModal.tsx renamed to frontend/src/components/@modal/EnterRoomModal.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { UserType } from '@customType/user';
77
import useSafeNavigate from '@hooks/useSafeNavigate';
88
import { PAGE_TYPE } from '@constants/page.constant';
99
import { useSetRecoilState } from 'recoil';
10-
import { meInRoomState, othersInRoomState } from '@store/room.store';
10+
import { meInRoomState, othersInRoomState, roomUUIDState } from '@store/room.store';
1111

1212
interface attendRoomResponseType {
1313
success?: boolean;
@@ -21,6 +21,7 @@ const EnterRoomModal = () => {
2121
const [errorMsg, setErrorMsg] = useState('');
2222
const setOthers = useSetRecoilState(othersInRoomState);
2323
const setMe = useSetRecoilState(meInRoomState);
24+
const setRoom = useSetRecoilState(roomUUIDState);
2425

2526
const { closeModal } = useModal();
2627
const { safeNavigate } = useSafeNavigate();
@@ -40,6 +41,7 @@ const EnterRoomModal = () => {
4041
closeModal();
4142
setOthers(others);
4243
setMe(me);
44+
setRoom(roomUUID);
4345
safeNavigate(PAGE_TYPE.LOBBY_PAGE);
4446
} catch (e) {
4547
setErrorMsg(e.message);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { css } from '@emotion/react';
2+
3+
export const docsListWrapperStyle = css`
4+
display: flex;
5+
flex-direction: column;
6+
gap: 15px;
7+
height: 80vh;
8+
width: 100%;
9+
`;
10+
11+
export const docsListHeaderStyle = css`
12+
display: flex;
13+
justify-content: space-between;
14+
`;
15+
16+
export const docsListBodyStyle = css`
17+
overflow: scroll;
18+
`;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import React from 'react';
2+
import Modal from '@components/@shared/Modal/Modal';
3+
import { useRecoilValue } from 'recoil';
4+
import { docsListQuery } from '@store/interviewDocs.store';
5+
import DocsItem from '@components/InterviewDocsItem/InterviewDocsItem';
6+
import Button from '@components/@shared/Button/Button';
7+
import {
8+
docsListBodyStyle,
9+
docsListHeaderStyle,
10+
docsListWrapperStyle,
11+
} from './InterviewDocsListModal.style';
12+
13+
const InterviewDocsListModal = () => {
14+
const docsList = useRecoilValue(docsListQuery(''));
15+
return (
16+
<Modal>
17+
<div css={docsListWrapperStyle}>
18+
<div css={docsListHeaderStyle}>
19+
<div>인터뷰 기록</div>
20+
<Button size="small">닫기</Button>
21+
</div>
22+
<div css={docsListBodyStyle}>
23+
{docsList.map((docs, idx) => (
24+
<DocsItem key={docs.id} docs={docs} idx={idx} style="list" />
25+
))}
26+
</div>
27+
</div>
28+
</Modal>
29+
);
30+
};
31+
32+
export default InterviewDocsListModal;
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { css } from '@emotion/react';
2+
3+
export const docsItemWrapperStyle = css`
4+
display: flex;
5+
flex-direction: column;
6+
gap: 15px;
7+
padding: 10px;
8+
height: 80vh;
9+
width: 100%;
10+
`;
11+
12+
export const docsItemHeaderStyle = css`
13+
display: flex;
14+
align-items: center;
15+
justify-content: space-between;
16+
`;
17+
18+
export const docsItemBtnsStyle = css`
19+
display: flex;
20+
`;
21+
22+
export const docsItemBodyStyle = css`
23+
display: flex;
24+
gap: 15px;
25+
`;
26+
27+
export const docsItemVideoAreaStyle = css`
28+
display: flex;
29+
flex-direction: column;
30+
gap: 15px;
31+
`;
32+
33+
export const docsItemVideoInfoStyle = css`
34+
display: flex;
35+
flex-direction: column;
36+
gap: 5px;
37+
div {
38+
display: 'flex';
39+
}
40+
`;
41+
42+
export const docsItemFbAreaStyle = css`
43+
display: flex;
44+
flex-direction: column;
45+
height: 100%;
46+
`;
47+
48+
export const docsItemFbBtnsStyle = css`
49+
display: flex;
50+
`;
51+
52+
export const docsItemFbListStyle = css`
53+
overflow: scroll;
54+
`;
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import React, { useState } from 'react';
2+
import Modal from '@components/@shared/Modal/Modal';
3+
import { useRecoilValue } from 'recoil';
4+
import { docsItemQuery } from '@store/interviewDocs.store';
5+
import Button from '@components/@shared/Button/Button';
6+
import Video from '@components/@shared/Video/Video';
7+
import FeedbackList from '@components/FeedbackList/FeedbackList';
8+
import { getFirstLabeledFbList } from '@utils/common.util';
9+
import {
10+
docsItemBodyStyle,
11+
docsItemBtnsStyle,
12+
docsItemFbAreaStyle,
13+
docsItemFbBtnsStyle,
14+
docsItemHeaderStyle,
15+
docsItemWrapperStyle,
16+
docsItemVideoAreaStyle,
17+
docsItemVideoInfoStyle,
18+
docsItemFbListStyle,
19+
} from './InterviewDocsModal.style';
20+
21+
interface Props {
22+
docsUUID: string;
23+
idx: number;
24+
}
25+
26+
const InterviewDocsModal = ({ docsUUID, idx }: Props) => {
27+
const docsItem = useRecoilValue(docsItemQuery(docsUUID));
28+
const { createdAt, videoPlayTime, feedbacks } = docsItem;
29+
const createdAtDate = new Date(createdAt);
30+
const [docIdx, setDocIdx] = useState(0);
31+
32+
const handleChangeDocIdx = (idx) => {
33+
setDocIdx(idx);
34+
};
35+
36+
return (
37+
<Modal>
38+
<div css={docsItemWrapperStyle}>
39+
<div css={docsItemHeaderStyle}>
40+
<div>#{idx}</div>
41+
<div>Sync</div>
42+
<div css={docsItemBtnsStyle}>
43+
<Button size="small">다운로드</Button>
44+
<Button size="small">닫기</Button>
45+
</div>
46+
</div>
47+
<div css={docsItemBodyStyle}>
48+
<div css={docsItemVideoAreaStyle}>
49+
<Video width={100} src="" />
50+
<div css={docsItemVideoInfoStyle}>
51+
<div>
52+
<div>일시</div>
53+
<div>{createdAtDate.toLocaleDateString()}</div>
54+
</div>
55+
<div>
56+
<div>면접 시간</div>
57+
<div>{videoPlayTime}</div>
58+
</div>
59+
<div>
60+
<div>면접자</div>
61+
<div>dummyUUID</div>
62+
</div>
63+
</div>
64+
</div>
65+
<div css={docsItemFbAreaStyle}>
66+
<div css={docsItemFbBtnsStyle}>
67+
{feedbacks.map((fb, i) => (
68+
<Button size="small" key={i} onClick={() => handleChangeDocIdx(i)}>
69+
{fb.nickname}
70+
</Button>
71+
))}
72+
</div>
73+
<div css={docsItemFbListStyle}>
74+
{feedbacks[docIdx] ? (
75+
<FeedbackList
76+
feedbackList={getFirstLabeledFbList(
77+
feedbacks[docIdx].feedbackList
78+
)}
79+
/>
80+
) : (
81+
<div>작성된 피드백이 없습니다.</div>
82+
)}
83+
</div>
84+
</div>
85+
</div>
86+
</div>
87+
</Modal>
88+
);
89+
};
90+
91+
export default InterviewDocsModal;
Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,42 @@
11
import React from 'react';
22
import { Story } from '@storybook/react';
3-
import Button, { buttonPropType } from '../Button/Button';
3+
import RoundButton, { roundButtonPropType } from './RoundButton';
44
import { ReactComponent as FolderIcon } from '@assets/icon/folder.svg';
5+
import { iconSmStyle } from '@styles/commonStyle';
6+
import theme from '@styles/theme';
57

68
export default {
7-
component: Button,
8-
title: '@shared/Button',
9+
component: RoundButton,
10+
title: '@shared/RoundButton',
911
};
1012

11-
const Template: Story<buttonPropType> = (args) => (
12-
<Button {...args}>
13+
const Template: Story<roundButtonPropType> = (args) => (
14+
<RoundButton {...args}>
1315
<span>Button</span>
14-
</Button>
16+
</RoundButton>
1517
);
16-
1718
export const Default = Template.bind({});
18-
Default.args = {};
19+
Default.args = {
20+
style: { backgroundColor: theme.colors.primary, width: 100, height: 50 },
21+
};
1922

20-
const IconTemplate: Story<buttonPropType> = (args) => (
21-
<Button {...args}>
22-
<FolderIcon />
23+
const IconTemplate: Story<roundButtonPropType> = (args) => (
24+
<RoundButton {...args}>
25+
<FolderIcon {...iconSmStyle} />
2326
<span>Button</span>
24-
</Button>
27+
</RoundButton>
2528
);
26-
2729
export const IconButton = IconTemplate.bind({});
28-
IconButton.args = {};
30+
IconButton.args = {
31+
style: { backgroundColor: theme.colors.primary, width: 130, height: 50 },
32+
};
2933

30-
const IconOnlyTemplate: Story<buttonPropType> = (args) => (
31-
<Button {...args}>
32-
<FolderIcon />
33-
</Button>
34+
const IconOnlyTemplate: Story<roundButtonPropType> = (args) => (
35+
<RoundButton {...args}>
36+
<FolderIcon {...iconSmStyle} />
37+
</RoundButton>
3438
);
35-
3639
export const IconOnlyButton = IconOnlyTemplate.bind({});
37-
IconButton.args = {};
40+
IconOnlyButton.args = {
41+
style: { backgroundColor: theme.colors.primary, width: 50, height: 50 },
42+
};
Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
import { css } from '@emotion/react';
2+
import theme from '@styles/theme';
23

34
export const roundButtonStyle = (style) => css`
45
display: flex;
56
box-sizing: border-box;
6-
justify-content: center;
7+
justify-content: space-around;
78
align-items: center;
89
910
width: ${style.width}px;
1011
height: ${style.height}px;
1112
border-radius: ${style.height / 2}px;
12-
background-color: ${style.backgroundColor};
13-
color: ${style.color};
14-
padding: 0px 30px;
13+
background-color: ${style.backgroundColor || theme.colors.primary};
14+
color: ${style.color || 'white'};
1515
font-size: ${style.fontsize || '24px'};
16+
17+
&:hover {
18+
filter: ${style.color === 'black' ? `brightness(200%)` : `brightness(110%)`};
19+
}
1620
`;

0 commit comments

Comments
 (0)