Skip to content

Commit 716773b

Browse files
authored
Merge pull request #299 from boostcampwm-2022/dev
Deploy: 5주차 데모 전 배포
2 parents ad6eb97 + 6b23eb6 commit 716773b

Some content is hidden

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

71 files changed

+1020
-807
lines changed

@wabinar/constants/package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "@wabinar/constants",
3+
"version": "1.0.0",
4+
"description": "CRDT for wabinar",
5+
"license": "MIT",
6+
"scripts": {
7+
"test": "jest"
8+
},
9+
"devDependencies": {
10+
"jest": "^29.3.1"
11+
}
12+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
export const WORKSPACE_EVENT = {
2+
START_MEETING: 'start-meeting',
3+
END_MEETING: 'end-meeting',
4+
SEND_HELLO: 'send-hello',
5+
RECEIVE_HELLO: 'receive-hello',
6+
SEND_OFFER: 'send-offer',
7+
RECEIVE_OFFER: 'receive-offer',
8+
SEND_ANSWER: 'send-answer',
9+
RECEIVE_ANSWER: 'receive-answer',
10+
SEND_ICE: 'send-ice',
11+
RECEIVE_ICE: 'receive-ice',
12+
RECEIVE_BYE: 'receive_bye',
13+
};
14+
15+
export const MOM_EVENT = {
16+
CREATE: 'create',
17+
SELECT: 'select',
18+
UPDATE_TITLE: 'update-mom-title',
19+
INIT: 'init-mom',
20+
INSERT_BLOCK: 'insert-block',
21+
DELETE_BLOCK: 'delete-block',
22+
UPDATED: 'updated-mom',
23+
};
24+
25+
export const BLOCK_EVENT = {
26+
INIT: 'init-block',
27+
LOAD_TYPE: 'load-type',
28+
UPDATE_TYPE: 'update-type',
29+
INSERT_TEXT: 'insert-text',
30+
DELETE_TEXT: 'delete-text',
31+
UPDATE_TEXT: 'update-text',
32+
CREATE_VOTE: 'create-vote',
33+
UPDATE_VOTE: 'update-vote',
34+
END_VOTE: 'end-vote',
35+
FETCH_QUESTIONS: 'fetch-questions',
36+
ADD_QUESTIONS: 'add-questions',
37+
RESOLVE_QUESTIONS: 'resolve-questions',
38+
};

client/src/components/QuestionBlock/index.tsx renamed to client/src/components/Block/QuestionBlock/index.tsx

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { BiCheckbox } from '@react-icons/all-files/bi/BiCheckbox';
22
import { BiCheckboxChecked } from '@react-icons/all-files/bi/BiCheckboxChecked';
3+
import { BLOCK_EVENT } from '@wabinar/constants/socket-message';
34
import classNames from 'classnames/bind';
45
import React, { useEffect, useState } from 'react';
56
import useSocketContext from 'src/hooks/useSocketContext';
@@ -14,7 +15,11 @@ interface Question {
1415
text: string;
1516
}
1617

17-
function QuestionBlock() {
18+
interface QuestionBlockProps {
19+
id: string;
20+
}
21+
22+
function QuestionBlock({ id }: QuestionBlockProps) {
1823
const [questions, setQuestions] = useState<Question[]>([]);
1924
const { momSocket: socket } = useSocketContext();
2025

@@ -27,27 +32,40 @@ function QuestionBlock() {
2732
isResolved: false,
2833
text: questionText,
2934
};
30-
socket.emit('question-block__add-question', question);
35+
36+
socket.emit(BLOCK_EVENT.ADD_QUESTIONS, id, question);
3137
};
3238

3339
useEffect(() => {
34-
socket.on('question-block__questions-fetched', fetchedQuestions => {
35-
setQuestions([...fetchedQuestions]);
40+
socket.on(`${BLOCK_EVENT.FETCH_QUESTIONS}-${id}`, (fetchedQuestions) => {
41+
setQuestions(fetchedQuestions ? [...fetchedQuestions] : []);
3642
});
3743

38-
socket.on('question-block__question-added', (questionToAdd) => {
39-
setQuestions(prev => [...prev, questionToAdd]);
44+
socket.on(`${BLOCK_EVENT.ADD_QUESTIONS}-${id}`, (questionToAdd) => {
45+
setQuestions((prev) => [...prev, questionToAdd]);
4046
});
4147

42-
socket.emit('question-block__fetch-questions');
48+
socket.emit(BLOCK_EVENT.FETCH_QUESTIONS, id);
49+
50+
return () => {
51+
socket.off(`${BLOCK_EVENT.FETCH_QUESTIONS}-${id}`);
52+
socket.off(`${BLOCK_EVENT.ADD_QUESTIONS}-${id}`);
53+
};
4354
}, []);
4455

4556
const onClick: React.MouseEventHandler<HTMLLIElement> = (e) => {
4657
const targetId = Number(e.currentTarget.id);
47-
const clickedQuestion = questions.filter(q => q.id === targetId)[0];
48-
const toggledResolved = !clickedQuestion.isResolved;
4958

50-
socket.emit('question-block__toggle-resolved', targetId, toggledResolved);
59+
const toggledQuestions = questions.map((q) => {
60+
if (q.id === targetId) {
61+
q.isResolved = !q.isResolved;
62+
}
63+
return q;
64+
});
65+
66+
setQuestions(toggledQuestions);
67+
68+
socket.emit(BLOCK_EVENT.RESOLVE_QUESTIONS, id, toggledQuestions);
5169
};
5270

5371
const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = (e) => {
@@ -80,7 +98,9 @@ function QuestionBlock() {
8098
) : (
8199
<BiCheckbox className={style['check-box']} />
82100
)}
83-
<p className={cx(questionText, { check: isResolved })}>{questionText}</p>
101+
<p className={cx(questionText, { check: isResolved })}>
102+
{questionText}
103+
</p>
84104
</li>
85105
))}
86106
</ul>

client/src/components/Mom/Block/TextBlock.tsx renamed to client/src/components/Block/TextBlock.tsx

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import { BlockType } from '@wabinar/api-types/block';
2+
import { BLOCK_EVENT } from '@wabinar/constants/socket-message';
23
import {
3-
RemoteInsertOperation,
44
RemoteDeleteOperation,
5+
RemoteInsertOperation,
56
} from '@wabinar/crdt/linked-list';
6-
import React, { useEffect, useRef, memo, useState } from 'react';
7+
import React, { memo, useEffect, useRef, useState } from 'react';
78
import BlockSelector from 'src/components/BlockSelector';
8-
import SOCKET_MESSAGE from 'src/constants/socket-message';
99
import { useCRDT } from 'src/hooks/useCRDT';
1010
import { useOffset } from 'src/hooks/useOffset';
1111
import useSocketContext from 'src/hooks/useSocketContext';
1212

13-
import ee from '../EventEmitter';
13+
import ee from '../Mom/EventEmitter';
1414

1515
interface BlockProps {
1616
id: string;
@@ -112,25 +112,37 @@ function TextBlock({
112112
useEffect(() => {
113113
registerRef(blockRef);
114114

115-
socket.emit(SOCKET_MESSAGE.BLOCK.INIT, id);
115+
socket.emit(BLOCK_EVENT.INIT, id);
116116

117-
ee.on(`${SOCKET_MESSAGE.BLOCK.INIT}-${id}`, onInitialize);
118-
ee.on(`${SOCKET_MESSAGE.BLOCK.UPDATE_TEXT}-${id}`, onInitialize);
119-
ee.on(`${SOCKET_MESSAGE.BLOCK.INSERT_TEXT}-${id}`, onInsert);
120-
ee.on(`${SOCKET_MESSAGE.BLOCK.DELETE_TEXT}-${id}`, onDelete);
117+
ee.on(`${BLOCK_EVENT.INIT}-${id}`, onInitialize);
118+
ee.on(`${BLOCK_EVENT.UPDATE_TEXT}-${id}`, onInitialize);
119+
ee.on(`${BLOCK_EVENT.INSERT_TEXT}-${id}`, onInsert);
120+
ee.on(`${BLOCK_EVENT.DELETE_TEXT}-${id}`, onDelete);
121121

122122
return () => {
123-
ee.off(`${SOCKET_MESSAGE.BLOCK.INIT}-${id}`, onInitialize);
124-
ee.off(`${SOCKET_MESSAGE.BLOCK.UPDATE_TEXT}-${id}`, onInitialize);
125-
ee.off(`${SOCKET_MESSAGE.BLOCK.INSERT_TEXT}-${id}`, onInsert);
126-
ee.off(`${SOCKET_MESSAGE.BLOCK.DELETE_TEXT}-${id}`, onDelete);
123+
ee.off(`${BLOCK_EVENT.INIT}-${id}`, onInitialize);
124+
ee.off(`${BLOCK_EVENT.UPDATE_TEXT}-${id}`, onInitialize);
125+
ee.off(`${BLOCK_EVENT.INSERT_TEXT}-${id}`, onInsert);
126+
ee.off(`${BLOCK_EVENT.DELETE_TEXT}-${id}`, onDelete);
127127
};
128128
}, []);
129129

130+
useEffect(() => {
131+
updateCaretPosition();
132+
}, [isOpen]);
133+
130134
// 로컬에서 일어나는 작성 - 삽입과 삭제 연산
131135
const onInput: React.FormEventHandler = (e) => {
132136
setOffset();
133137

138+
if (!blockRef.current) return;
139+
140+
if (blockRef.current.innerText === '/') {
141+
setIsOpen(true);
142+
} else if (isOpen) {
143+
setIsOpen(false);
144+
}
145+
134146
if (offsetRef.current === null) return;
135147

136148
const event = e.nativeEvent as InputEvent;
@@ -139,15 +151,15 @@ function TextBlock({
139151

140152
if (event.inputType === 'deleteContentBackward') {
141153
const remoteDeletion = localDeleteCRDT(offsetRef.current);
142-
socket.emit(SOCKET_MESSAGE.BLOCK.DELETE_TEXT, id, remoteDeletion);
154+
socket.emit(BLOCK_EVENT.DELETE_TEXT, id, remoteDeletion);
143155
return;
144156
}
145157

146158
const letter = event.data as string;
147159
const previousLetterIndex = offsetRef.current - 2;
148160
const remoteInsertion = localInsertCRDT(previousLetterIndex, letter);
149161

150-
socket.emit(SOCKET_MESSAGE.BLOCK.INSERT_TEXT, id, remoteInsertion);
162+
socket.emit(BLOCK_EVENT.INSERT_TEXT, id, remoteInsertion);
151163
};
152164

153165
// 한글 입력 핸들링
@@ -165,7 +177,7 @@ function TextBlock({
165177

166178
const remoteInsertion = localInsertCRDT(previousLetterIndex, letter);
167179

168-
socket.emit(SOCKET_MESSAGE.BLOCK.INSERT_TEXT, id, remoteInsertion);
180+
socket.emit(BLOCK_EVENT.INSERT_TEXT, id, remoteInsertion);
169181
});
170182
};
171183

@@ -187,7 +199,7 @@ function TextBlock({
187199
.split('')
188200
.map((letter) => localInsertCRDT(previousLetterIndex++, letter));
189201

190-
socket.emit(SOCKET_MESSAGE.BLOCK.UPDATE_TEXT, id, remoteInsertions);
202+
socket.emit(BLOCK_EVENT.UPDATE_TEXT, id, remoteInsertions);
191203

192204
blockRef.current.innerText = previousText + pastedText + nextText;
193205
updateCaretPosition(pastedText.length);
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { BLOCK_EVENT } from '@wabinar/constants/socket-message';
2+
import { useState, useEffect } from 'react';
3+
import VoteBlockTemplate from 'src/components/common/Templates/VoteBlock';
4+
import { VoteMode } from 'src/constants/block';
5+
import useSocketContext from 'src/hooks/useSocketContext';
6+
import { Option } from 'src/types/block';
7+
8+
interface VoteBlockProps {
9+
id: string;
10+
}
11+
12+
function VoteBlock({ id }: VoteBlockProps) {
13+
const { momSocket: socket } = useSocketContext();
14+
15+
const [voteMode, setVoteMode] = useState<VoteMode>(VoteMode.CREATE);
16+
const initialOption: Option[] = [{ id: 1, text: '', count: 0 }];
17+
const [options, setOptions] = useState<Option[]>(initialOption);
18+
19+
useEffect(() => {
20+
socket.on(BLOCK_EVENT.CREATE_VOTE, (options) => {
21+
setVoteMode(VoteMode.REGISTERED as VoteMode);
22+
setOptions(options);
23+
});
24+
}, []);
25+
26+
return (
27+
<VoteBlockTemplate
28+
id={id}
29+
mode={voteMode}
30+
setVoteMode={setVoteMode}
31+
options={options}
32+
setOptions={setOptions}
33+
/>
34+
);
35+
}
36+
37+
export default VoteBlock;

client/src/components/Mom/Block/index.tsx renamed to client/src/components/Block/index.tsx

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import { useState, useEffect, memo, useRef } from 'react';
2-
import SOCKET_MESSAGE from 'src/constants/socket-message';
1+
import { BLOCK_EVENT } from '@wabinar/constants/socket-message';
2+
import ee from 'components/Mom/EventEmitter';
3+
import { memo, useEffect, useRef, useState } from 'react';
34
import useSocketContext from 'src/hooks/useSocketContext';
45

5-
import ee from '../EventEmitter';
6+
import QuestionBlock from './QuestionBlock';
67
import TextBlock from './TextBlock';
8+
import VoteBlock from './VoteBlock';
79

810
export enum BlockType {
911
H1,
@@ -28,25 +30,23 @@ function Block({ id, index, onKeyDown, registerRef }: BlockProps) {
2830
const localUpdateFlagRef = useRef<boolean>(false);
2931

3032
useEffect(() => {
31-
socket.emit(SOCKET_MESSAGE.BLOCK.LOAD_TYPE, id, (type: BlockType) =>
32-
setType(type),
33-
);
33+
socket.emit(BLOCK_EVENT.LOAD_TYPE, id, (type: BlockType) => setType(type));
3434

35-
ee.on(`${SOCKET_MESSAGE.BLOCK.UPDATE_TYPE}-${id}`, (type) => {
35+
ee.on(`${BLOCK_EVENT.UPDATE_TYPE}-${id}`, (type) => {
3636
setType(type);
3737
localUpdateFlagRef.current = false;
3838
});
3939
}, []);
4040

4141
useEffect(() => {
4242
if (localUpdateFlagRef.current) {
43-
socket.emit(SOCKET_MESSAGE.BLOCK.UPDATE_TYPE, id, type);
43+
socket.emit(BLOCK_EVENT.UPDATE_TYPE, id, type);
4444
}
4545
}, [type]);
4646

47-
const setBlockType = (id: BlockType) => {
47+
const setBlockType = (type: BlockType) => {
4848
localUpdateFlagRef.current = true;
49-
setType(id);
49+
setType(type);
5050
};
5151

5252
switch (type) {
@@ -64,6 +64,10 @@ function Block({ id, index, onKeyDown, registerRef }: BlockProps) {
6464
registerRef={registerRef}
6565
/>
6666
);
67+
case BlockType.VOTE:
68+
return <VoteBlock id={id} />;
69+
case BlockType.QUESTION:
70+
return <QuestionBlock id={id} />;
6771
default:
6872
return <p />;
6973
}

client/src/components/ConfMediaBar/ConfMedia/index.tsx renamed to client/src/components/MeetingMediaBar/MeetingMedia/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ interface MediaProps {
77
muted: boolean;
88
}
99

10-
function ConfMedia({ stream, muted }: MediaProps) {
10+
function MeetingMedia({ stream, muted }: MediaProps) {
1111
const ref = useRef<HTMLVideoElement>(null);
1212

1313
useEffect(() => {
@@ -18,4 +18,4 @@ function ConfMedia({ stream, muted }: MediaProps) {
1818
return <video className={style.video} ref={ref} muted={muted} autoPlay />;
1919
}
2020

21-
export default memo(ConfMedia);
21+
export default memo(MeetingMedia);

0 commit comments

Comments
 (0)