Skip to content

Commit 6b23eb6

Browse files
se030dohun31wcho21juyeong-s
authored
Feat/#268-BK: 회의록에 투표와 질문 블럭 연동 (#296)
* feat: Block에서 질문 블럭 반환 * feat: 질문 블럭 연동을 위해 서비스 로직 수정 - 질문 해결 로직은 클라이언트에서 반영해서 questions 배열 전체를 보내도록 함 - 해당 회의록을 보고있는 클라이언트들에게 해당 질문 블럭 fetch 이벤트 전송 Co-authored-by: hodun <[email protected]> * feat: 투표 블럭 연동 - 서비스 로직 개선 필요 * fix: CI 임시 해결 Co-authored-by: hodun <[email protected]> * fix: 투표 모드 enum 사용 * chore: Block 컴포넌트 디렉토리 구조 변경 * fix: setType 인자 네이밍 id에서 type으로 수정 * fix: VoteBlock 항상 보이게 수정 Co-authored-by: hodun <[email protected]> Co-authored-by: Won-hee Cho <[email protected]> * fix: CRDT 에러 방지 핸들러 (temp) Co-authored-by: hodun <[email protected]> Co-authored-by: Won-hee Cho <[email protected]> Co-authored-by: Ruby <[email protected]> Co-authored-by: hodun <[email protected]> Co-authored-by: Won-hee Cho <[email protected]> Co-authored-by: Ruby <[email protected]>
1 parent 61823aa commit 6b23eb6

File tree

16 files changed

+173
-97
lines changed

16 files changed

+173
-97
lines changed

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

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ interface Question {
1515
text: string;
1616
}
1717

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

@@ -28,27 +32,40 @@ function QuestionBlock() {
2832
isResolved: false,
2933
text: questionText,
3034
};
31-
socket.emit(BLOCK_EVENT.ADD_QUESTIONS, question);
35+
36+
socket.emit(BLOCK_EVENT.ADD_QUESTIONS, id, question);
3237
};
3338

3439
useEffect(() => {
35-
socket.on(BLOCK_EVENT.FETCH_QUESTIONS, (fetchedQuestions) => {
36-
setQuestions([...fetchedQuestions]);
40+
socket.on(`${BLOCK_EVENT.FETCH_QUESTIONS}-${id}`, (fetchedQuestions) => {
41+
setQuestions(fetchedQuestions ? [...fetchedQuestions] : []);
3742
});
3843

39-
socket.on(BLOCK_EVENT.ADD_QUESTIONS, (questionToAdd) => {
44+
socket.on(`${BLOCK_EVENT.ADD_QUESTIONS}-${id}`, (questionToAdd) => {
4045
setQuestions((prev) => [...prev, questionToAdd]);
4146
});
4247

43-
socket.emit(BLOCK_EVENT.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+
};
4454
}, []);
4555

4656
const onClick: React.MouseEventHandler<HTMLLIElement> = (e) => {
4757
const targetId = Number(e.currentTarget.id);
48-
const clickedQuestion = questions.filter((q) => q.id === targetId)[0];
49-
const toggledResolved = !clickedQuestion.isResolved;
5058

51-
socket.emit(BLOCK_EVENT.RESOLVE_QUESTIONS, 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);
5269
};
5370

5471
const onKeyDown: React.KeyboardEventHandler<HTMLInputElement> = (e) => {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ 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;
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: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { BLOCK_EVENT } from '@wabinar/constants/socket-message';
2+
import ee from 'components/Mom/EventEmitter';
23
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,
@@ -42,9 +44,9 @@ function Block({ id, index, onKeyDown, registerRef }: BlockProps) {
4244
}
4345
}, [type]);
4446

45-
const setBlockType = (id: BlockType) => {
47+
const setBlockType = (type: BlockType) => {
4648
localUpdateFlagRef.current = true;
47-
setType(id);
49+
setType(type);
4850
};
4951

5052
switch (type) {
@@ -62,6 +64,10 @@ function Block({ id, index, onKeyDown, registerRef }: BlockProps) {
6264
registerRef={registerRef}
6365
/>
6466
);
67+
case BlockType.VOTE:
68+
return <VoteBlock id={id} />;
69+
case BlockType.QUESTION:
70+
return <QuestionBlock id={id} />;
6571
default:
6672
return <p />;
6773
}

client/src/components/Mom/index.tsx

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
import { BLOCK_EVENT, MOM_EVENT } from '@wabinar/constants/socket-message';
2+
import Block from 'components/Block';
23
import { useEffect, useRef, useState } from 'react';
3-
import { VOTE_MODE } from 'src/constants/block';
44
import { useCRDT } from 'src/hooks/useCRDT';
55
import useDebounce from 'src/hooks/useDebounce';
66
import useSelectedMom from 'src/hooks/useSelectedMom';
77
import useSocketContext from 'src/hooks/useSocketContext';
8-
import { Option, VoteMode } from 'src/types/block';
98
import { v4 as uuid } from 'uuid';
109

11-
import Block from './Block';
1210
import DefaultMom from './DefaultMom';
1311
import ee from './EventEmitter';
1412
import style from './style.module.scss';
@@ -17,8 +15,6 @@ function Mom() {
1715
const { selectedMom } = useSelectedMom();
1816
const { momSocket: socket } = useSocketContext();
1917

20-
const [voteMode, setVoteMode] = useState<VoteMode | null>(null);
21-
2218
const {
2319
syncCRDT,
2420
spreadCRDT,
@@ -115,9 +111,6 @@ function Mom() {
115111
}
116112
};
117113

118-
const initialOption: Option[] = [{ id: 1, text: '', count: 0 }];
119-
const [options, setOptions] = useState<Option[]>(initialOption);
120-
121114
useEffect(() => {
122115
setBlockFocus();
123116
}, [blocks]);
@@ -176,11 +169,6 @@ function Mom() {
176169
ee.emit(`${BLOCK_EVENT.UPDATE_TYPE}-${id}`, type);
177170
});
178171

179-
socket.on(BLOCK_EVENT.CREATE_VOTE, (options) => {
180-
setVoteMode(VOTE_MODE.REGISTERED as VoteMode);
181-
setOptions(options);
182-
});
183-
184172
return () => {
185173
[
186174
MOM_EVENT.INIT,
@@ -192,7 +180,6 @@ function Mom() {
192180
BLOCK_EVENT.INSERT_TEXT,
193181
BLOCK_EVENT.DELETE_TEXT,
194182
BLOCK_EVENT.UPDATE_TYPE,
195-
BLOCK_EVENT.CREATE_VOTE,
196183
].forEach((event) => socket.off(event));
197184
};
198185
}, [selectedMom]);

client/src/components/common/Templates/VoteBlock/index.tsx

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,40 +4,40 @@ import classNames from 'classnames/bind';
44
import Button from 'common/Button';
55
import { ChangeEventHandler, useEffect, useState } from 'react';
66
import { toast } from 'react-toastify';
7-
import { VOTE_MODE } from 'src/constants/block';
7+
import { VoteMode } from 'src/constants/block';
88
import useDebounceInput from 'src/hooks/useDebounceInput';
9-
import useSelectedMom from 'src/hooks/useSelectedMom';
109
import useSocketContext from 'src/hooks/useSocketContext';
1110
import { useUserContext } from 'src/hooks/useUserContext';
12-
import { Option, VoteMode } from 'src/types/block';
11+
import { Option } from 'src/types/block';
1312
import color from 'styles/color.module.scss';
1413

1514
import style from './style.module.scss';
1615

1716
const cx = classNames.bind(style);
1817

1918
interface VoteBlockProps {
19+
id: string;
2020
mode: VoteMode;
21-
setVoteMode: React.Dispatch<React.SetStateAction<VoteMode | null>>;
21+
setVoteMode: React.Dispatch<React.SetStateAction<VoteMode>>;
2222
options: Option[];
2323
setOptions: React.Dispatch<React.SetStateAction<Option[]>>;
2424
}
2525

2626
function VoteBlockTemplate({
27+
id,
2728
mode,
2829
setVoteMode,
2930
options,
3031
setOptions,
3132
}: VoteBlockProps) {
3233
const [isCreateMode, isRegisteredMode, isEndMode] = [
33-
mode === VOTE_MODE.CREATE,
34-
mode === VOTE_MODE.REGISTERED,
35-
mode === VOTE_MODE.END,
34+
mode === VoteMode.CREATE,
35+
mode === VoteMode.REGISTERED,
36+
mode === VoteMode.END,
3637
];
3738

3839
const { user } = useUserContext();
3940
const { momSocket: socket } = useSocketContext();
40-
const { selectedMom } = useSelectedMom();
4141

4242
const [selectedOptionId, setSelectedOptionId] = useState<number | null>(null);
4343
const [participantCount, setParticipantCount] = useState(0);
@@ -65,7 +65,7 @@ function VoteBlockTemplate({
6565
}
6666

6767
setOptions(validOptions);
68-
setVoteMode('registered');
68+
setVoteMode(VoteMode.REGISTERED);
6969

7070
socket.emit(BLOCK_EVENT.CREATE_VOTE, validOptions);
7171

@@ -118,9 +118,9 @@ function VoteBlockTemplate({
118118
});
119119

120120
socket.on(BLOCK_EVENT.END_VOTE, ({ options, participantCount }) => {
121-
setVoteMode('end');
121+
setVoteMode(VoteMode.END);
122122
setOptions(options);
123-
setParticipantCount(Number(participantCount));
123+
setParticipantCount(participantCount);
124124
toast('투표가 종료되었어요 ^^');
125125
});
126126

@@ -171,7 +171,7 @@ function VoteBlockTemplate({
171171
<input
172172
type="text"
173173
className={cx('option-input', {
174-
'cursor-enable': !isCreateMode,
174+
selected: isRegisteredMode,
175175
})}
176176
placeholder="항목을 입력해주세요"
177177
onChange={onChange}

client/src/constants/block.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ export const BLOCKS_TYPE = [
3737
},
3838
];
3939

40-
export const VOTE_MODE = {
41-
CREATE: 'create',
42-
REGISTERED: 'registered',
43-
END: 'end',
44-
};
40+
export enum VoteMode {
41+
CREATE,
42+
REGISTERED,
43+
END,
44+
}

client/src/types/block.d.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
export type VoteMode = 'create' | 'registered' | 'end';
2-
31
export interface Option {
42
id: number;
53
text: string;

server/apis/mom/block/model.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ import { Schema } from 'mongoose';
33
import { BlockType } from '@wabinar/api-types/block';
44

55
import { Vote } from '../vote/service';
6-
import { Question } from '../questions/service';
6+
import { Question } from './question/service';
77

88
interface Block {
99
id: string;
1010
type: BlockType;
1111
head: Object;
1212
nodeMap: Object;
1313
voteProperties: Vote;
14-
questionProperties: Question;
14+
questionProperties: Question[];
1515
}
1616

1717
const blockSchema = new Schema<Block>({
@@ -20,7 +20,7 @@ const blockSchema = new Schema<Block>({
2020
head: { type: Object, default: null },
2121
nodeMap: { type: Object, default: {} },
2222
voteProperties: { type: Object, default: {} },
23-
questionProperties: { type: Object, default: {} },
23+
questionProperties: { type: [Object], default: [] },
2424
});
2525

2626
const blockModel = mongoose.model('Block', blockSchema);

0 commit comments

Comments
 (0)