Skip to content

Commit fed21fd

Browse files
authored
Merge pull request #797 from depromeet/develop
Release-2.0.3
2 parents dc0c631 + 2489a37 commit fed21fd

File tree

9 files changed

+104
-96
lines changed

9 files changed

+104
-96
lines changed

apps/mobile/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "@layer/mobile",
33
"main": "expo-router/entry",
44
"types": "./bridge/native.ts",
5-
"version": "1.0.2",
5+
"version": "2.0.3",
66
"scripts": {
77
"start": "expo start",
88
"reset-project": "node ./scripts/reset-project.js",

apps/web/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@layer/web",
33
"private": true,
4-
"version": "2.0.0",
4+
"version": "2.0.3",
55
"type": "module",
66
"scripts": {
77
"dev": "vite",

apps/web/src/app/desktop/component/home/RetrospectCard/index.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import { PATHS } from "@layer/shared";
1010
import { useFunnelModal } from "@/hooks/useFunnelModal";
1111
import { Prepare } from "../../retrospectWrite/prepare";
1212
import TemplateCardManageToggleMenu from "@/component/retrospect/template/card/TemplateCardManageToggleMenu";
13+
import { isSpaceLeader } from "@/utils/userUtil";
14+
import { useAtomValue } from "jotai";
15+
import { currentSpaceState } from "@/store/space/spaceAtom";
1316

1417
interface RetrospectCardProps {
1518
retrospect: Retrospect;
@@ -20,6 +23,9 @@ export default function RetrospectCard({ retrospect, spaceId }: RetrospectCardPr
2023
const navigate = useNavigate();
2124
const [searchParams] = useSearchParams();
2225
const { openFunnelModal } = useFunnelModal();
26+
const currentSelectedSpace = useAtomValue(currentSpaceState);
27+
const { leader } = currentSelectedSpace || {};
28+
const isLeader = isSpaceLeader(leader?.id);
2329

2430
const {
2531
spaceId: retrospectSpaceId,
@@ -70,7 +76,7 @@ export default function RetrospectCard({ retrospect, spaceId }: RetrospectCardPr
7076
display: flex;
7177
flex-direction: column;
7278
width: 29.6rem;
73-
height: fit-content;
79+
height: 13.8rem;
7480
max-height: 13.8rem;
7581
padding: 1.6rem;
7682
background-color: white;
@@ -98,7 +104,7 @@ export default function RetrospectCard({ retrospect, spaceId }: RetrospectCardPr
98104
`}
99105
>
100106
<ProceedingTextBox writeStatus={writeStatus} analysisStatus={analysisStatus} />
101-
<TemplateCardManageToggleMenu retrospect={retrospect} />
107+
<TemplateCardManageToggleMenu retrospect={retrospect} isLeader={isLeader} />
102108
</div>
103109

104110
{/* ---------- 제목 ---------- */}
@@ -134,7 +140,7 @@ export default function RetrospectCard({ retrospect, spaceId }: RetrospectCardPr
134140
display: flex;
135141
justify-content: space-between;
136142
align-items: center;
137-
margin-top: 0.8rem;
143+
margin-top: auto;
138144
`}
139145
>
140146
<Typography variant="body12SemiBold" color="gray500">

apps/web/src/app/desktop/component/retrospectCreate/QuestionEditSection/AddQuestionView.tsx

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,43 @@ import { useToast } from "@/hooks/useToast";
1414
import { DESIGN_TOKEN_COLOR } from "@/style/designTokens";
1515

1616
type AddQuestionViewProps = {
17-
onAddQuestion: (content: string) => void;
18-
onAddMultipleQuestions: (contents: string[]) => void;
17+
onAddQuestions: (contents: string[]) => void;
1918
maxCount: number;
2019
};
2120

22-
export default function AddQuestionView({ onAddQuestion, onAddMultipleQuestions, maxCount }: AddQuestionViewProps) {
21+
export default function AddQuestionView({ onAddQuestions, maxCount }: AddQuestionViewProps) {
2322
const { toast } = useToast();
2423
const { tabs, curTab, selectTab } = useTabs(["직접작성", "추천질문"] as const);
2524
const { value: customQuestion, handleInputChange: handleCustomChange, resetInput } = useInput();
2625
const { tabs: categoryTabs, curTab: curCategoryTab, selectTab: selectCategoryTab } = useTabs(QUESTION_TYPES);
27-
const { selectedValues, isChecked, toggle } = useCheckBox();
26+
const { selectedValues, isChecked, toggle, resetChecked } = useCheckBox();
2827

29-
const handleDirectAdd = () => {
30-
if (customQuestion.trim()) {
31-
onAddQuestion(customQuestion);
28+
const handleAddQuestion = () => {
29+
const hasCustomQuestion = customQuestion.trim().length > 0;
30+
const hasSelectedQuestions = selectedValues.length > 0;
31+
32+
if (!hasCustomQuestion && !hasSelectedQuestions) {
33+
return;
34+
}
35+
36+
const questionsToAdd: string[] = [];
37+
38+
if (hasCustomQuestion) {
39+
questionsToAdd.push(customQuestion.trim());
40+
}
41+
42+
if (hasSelectedQuestions) {
43+
questionsToAdd.push(...selectedValues);
44+
}
45+
46+
onAddQuestions(questionsToAdd);
47+
48+
if (hasCustomQuestion) {
3249
resetInput();
3350
}
34-
};
3551

36-
const handleRecommendedAdd = () => {
37-
if (selectedValues.length > 0) {
38-
onAddMultipleQuestions(selectedValues);
52+
if (hasSelectedQuestions) {
53+
resetChecked();
3954
}
4055
};
4156

@@ -130,7 +145,7 @@ export default function AddQuestionView({ onAddQuestion, onAddMultipleQuestions,
130145
padding: 0;
131146
`}
132147
>
133-
<ButtonProvider.Primary onClick={curTab === "직접작성" ? handleDirectAdd : handleRecommendedAdd}>
148+
<ButtonProvider.Primary onClick={handleAddQuestion} disabled={customQuestion.trim().length === 0 && selectedValues.length === 0}>
134149
{selectedValues.length > 0 ? (
135150
<span>
136151
추가하기

apps/web/src/app/desktop/component/retrospectCreate/QuestionEditSection/index.tsx

Lines changed: 52 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState, useEffect } from "react";
1+
import { useState, useEffect, useCallback } from "react";
22
import { Button, ButtonProvider } from "@/component/common/button";
33
import { Icon } from "@/component/common/Icon";
44
import { Spacing } from "@/component/common/Spacing";
@@ -19,6 +19,8 @@ import AddQuestionView from "./AddQuestionView";
1919
import { useModal } from "@/hooks/useModal";
2020
import { isEqual } from "lodash-es";
2121

22+
const MAX_QUESTION_COUNT = 10;
23+
2224
type QuestionEditSectionProps = {
2325
onClose: () => void;
2426
};
@@ -95,36 +97,56 @@ export default function QuestionEditSection({ onClose }: QuestionEditSectionProp
9597
const handleDelete = (index: number) => {
9698
const updatedQuestions = questions.filter((_, i) => i !== index);
9799
setEditingQuestions(updatedQuestions);
98-
toast.success("삭제가 완료되었어요!");
99100
};
100101

101102
/**
102103
* 새 질문 추가 핸들러
103104
*/
104105
const handleAddQuestion = () => {
105-
if (questions.length >= 10) return;
106+
if (questions.length >= MAX_QUESTION_COUNT) return;
106107

107108
// 현재 질문들을 백업하고 질문 추가 모드로 전환
108-
setBackupQuestions([...questions]);
109+
const questionsToBackup = [...questions];
110+
setBackupQuestions(questionsToBackup);
109111
setIsAddMode(true);
112+
113+
const cancelCallback = () => {
114+
setEditingQuestions(questionsToBackup);
115+
setIsAddMode(false);
116+
setBackupQuestions([]);
117+
setModalDataState((prev) => ({
118+
...prev,
119+
title: "질문 리스트",
120+
options: {
121+
enableFooter: false,
122+
needsBackButton: true,
123+
backButtonCallback: handleCancel,
124+
},
125+
}));
126+
};
127+
110128
setModalDataState((prev) => ({
111129
...prev,
112130
title: "질문 추가",
113-
onClose: handleAddQuestionCancel,
131+
onClose: cancelCallback,
114132
options: {
115133
enableFooter: false,
116134
needsBackButton: true,
117135
disabledClose: true,
118-
backButtonCallback: handleAddQuestionCancel,
136+
backButtonCallback: cancelCallback,
119137
},
120138
}));
121139
};
122140

123141
/**
124-
* 질문 추가 완료 핸들러 (단일)
142+
* 질문 추가 완료 핸들러
125143
*/
126-
const handleAddQuestionComplete = (content: string) => {
127-
const newQuestions = [...questions, { questionType: "plain_text" as const, questionContent: content }];
144+
const handleAddQuestions = (contents: string[]) => {
145+
const newQuestionObjects = contents.map((content) => ({
146+
questionType: "plain_text" as const,
147+
questionContent: content,
148+
}));
149+
const newQuestions = [...questions, ...newQuestionObjects];
128150
setEditingQuestions(newQuestions);
129151

130152
// 원래 모드로 돌아가고 모달 제목 복원
@@ -142,32 +164,10 @@ export default function QuestionEditSection({ onClose }: QuestionEditSectionProp
142164
toast.success("질문이 추가되었어요!");
143165
};
144166

145-
/**
146-
* 질문 추가 완료 핸들러 (복수)
147-
*/
148-
const handleAddMultipleQuestions = (contents: string[]) => {
149-
const newQuestionObjects = contents.map((content) => ({
150-
questionType: "plain_text" as const,
151-
questionContent: content,
152-
}));
153-
const newQuestions = [...questions, ...newQuestionObjects];
154-
setEditingQuestions(newQuestions);
155-
156-
// 원래 모드로 돌아가고 모달 제목 복원
157-
setIsAddMode(false);
158-
setModalDataState((prev) => ({
159-
...prev,
160-
title: "질문 리스트",
161-
enableFooter: false,
162-
}));
163-
164-
toast.success(`${contents.length}개의 질문이 추가되었어요!`);
165-
};
166-
167167
/**
168168
* 질문 수정 취소 핸들러 (뒤로가기 버튼)
169169
*/
170-
const handleCancel = () => {
170+
const handleCancel = useCallback(() => {
171171
const hasChanged = !isEqual(originalQuestions, editingQuestions);
172172

173173
if (hasChanged) {
@@ -186,35 +186,7 @@ export default function QuestionEditSection({ onClose }: QuestionEditSectionProp
186186
} else {
187187
onClose();
188188
}
189-
};
190-
191-
/**
192-
* 질문 추가 취소 핸들러
193-
*/
194-
const handleAddQuestionCancel = () => {
195-
openExitWarningModal({
196-
title: "질문 추가를 취소하시겠어요?",
197-
contents: "추가중인 내용은 모두 사라져요",
198-
onConfirm: () => {
199-
// 백업된 질문들로 복원
200-
setEditingQuestions(backupQuestions);
201-
setIsAddMode(false);
202-
setBackupQuestions([]);
203-
setModalDataState((prev) => ({
204-
...prev,
205-
title: "질문 리스트",
206-
options: {
207-
enableFooter: false,
208-
needsBackButton: true,
209-
backButtonCallback: handleCancel,
210-
},
211-
}));
212-
},
213-
options: {
214-
buttonText: ["취소", "나가기"],
215-
},
216-
});
217-
};
189+
}, [originalQuestions, editingQuestions, onClose, openExitWarningModal]);
218190

219191
/**
220192
* 삭제 모드 진입 핸들러
@@ -239,8 +211,13 @@ export default function QuestionEditSection({ onClose }: QuestionEditSectionProp
239211
* 삭제 모드 완료 핸들러
240212
*/
241213
const handleDeleteModeComplete = () => {
214+
const hasDeleted = questions.length < backupQuestions.length;
242215
setIsDeleteMode(false);
243216
setBackupQuestions([]);
217+
218+
if (hasDeleted) {
219+
toast.success("삭제가 완료되었어요!");
220+
}
244221
};
245222

246223
// 제출 완료 핸들러
@@ -263,27 +240,25 @@ export default function QuestionEditSection({ onClose }: QuestionEditSectionProp
263240
onClose();
264241
};
265242

266-
// 모달의 뒤로가기 버튼 콜백을 handleCancel로 설정
243+
// 모달의 뒤로가기 버튼과 닫기 버튼 콜백을 handleCancel로 설정
267244
useEffect(() => {
268245
if (!isAddMode) {
269246
setModalDataState((prev) => ({
270247
...prev,
248+
onClose: handleCancel,
271249
options: {
272250
...prev.options,
251+
disabledClose: true,
273252
backButtonCallback: handleCancel,
274253
},
275254
}));
276255
}
277-
}, [editingQuestions, isAddMode]);
256+
}, [isAddMode, handleCancel]);
278257

279258
return (
280259
<>
281260
{isAddMode ? (
282-
<AddQuestionView
283-
onAddQuestion={handleAddQuestionComplete}
284-
onAddMultipleQuestions={handleAddMultipleQuestions}
285-
maxCount={10 - questions.length}
286-
/>
261+
<AddQuestionView onAddQuestions={handleAddQuestions} maxCount={MAX_QUESTION_COUNT - questions.length} />
287262
) : (
288263
<>
289264
<section
@@ -317,9 +292,9 @@ export default function QuestionEditSection({ onClose }: QuestionEditSectionProp
317292
{/* ---------- 추가 버튼 ---------- */}
318293
<button
319294
onClick={handleAddQuestion}
320-
disabled={questions.length >= 10}
295+
disabled={questions.length >= MAX_QUESTION_COUNT}
321296
css={css`
322-
background-color: ${questions.length >= 10 ? DESIGN_TOKEN_COLOR.gray200 : DESIGN_TOKEN_COLOR.blue100};
297+
background-color: ${questions.length >= MAX_QUESTION_COUNT ? DESIGN_TOKEN_COLOR.gray200 : DESIGN_TOKEN_COLOR.blue100};
323298
border-radius: 1.2rem;
324299
border: none;
325300
display: flex;
@@ -328,14 +303,17 @@ export default function QuestionEditSection({ onClose }: QuestionEditSectionProp
328303
height: 4.8rem;
329304
width: 100%;
330305
transition: background-color 0.2s ease;
331-
cursor: ${questions.length >= 10 ? "not-allowed" : "pointer"};
332-
306+
cursor: ${questions.length >= MAX_QUESTION_COUNT ? "not-allowed" : "pointer"};
333307
&:hover {
334-
background-color: ${questions.length >= 10 ? DESIGN_TOKEN_COLOR.gray200 : DESIGN_TOKEN_COLOR.blue200};
308+
background-color: ${questions.length >= MAX_QUESTION_COUNT ? DESIGN_TOKEN_COLOR.gray200 : DESIGN_TOKEN_COLOR.blue200};
335309
}
336310
`}
337311
>
338-
<Icon icon="ic_plus_thin" size={1.8} color={questions.length >= 10 ? DESIGN_TOKEN_COLOR.gray400 : DESIGN_TOKEN_COLOR.blue600} />
312+
<Icon
313+
icon="ic_plus_thin"
314+
size={1.8}
315+
color={questions.length >= MAX_QUESTION_COUNT ? DESIGN_TOKEN_COLOR.gray400 : DESIGN_TOKEN_COLOR.blue600}
316+
/>
339317
</button>
340318
</section>
341319
</section>

apps/web/src/component/retrospect/template/card/TemplateCardManageToggleMenu.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@ export default function TemplateCardManageToggleMenu({
2222
iconSize = 2.0,
2323
iconColor = "gray500",
2424
retrospect,
25+
isLeader,
2526
}: {
2627
iconSize?: number | string;
2728
iconColor?: keyof typeof DESIGN_TOKEN_COLOR;
2829
retrospect: Retrospect;
30+
isLeader: boolean;
2931
}) {
3032
const { isShowMenu, showMenu } = useToggleMenu();
3133
const { mutateAsync: mutateDeleteRetrospect } = useApiDeleteRetrospect();
@@ -77,6 +79,9 @@ export default function TemplateCardManageToggleMenu({
7779
}
7880
};
7981

82+
// * 회고 카드 관리 메뉴의 경우, 스페이스 리더에게만 노출되도록 합니다.
83+
if (!isLeader) return null;
84+
8085
return (
8186
<div
8287
css={css`

lerna.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
{
22
"npmClient": "pnpm",
3-
"packages": [".", "packages/*", "apps/*"],
4-
"version": "2.0.0"
5-
}
3+
"packages": [
4+
".",
5+
"packages/*",
6+
"apps/*"
7+
],
8+
"version": "2.0.3"
9+
}

0 commit comments

Comments
 (0)