Skip to content

Commit b6b4e92

Browse files
committed
refactor: topic, sticker store 분리
1 parent 49f4b6f commit b6b4e92

12 files changed

Lines changed: 93 additions & 79 deletions

File tree

apps/web/src/components/(with-side-bar)/layout/add-topic-modal.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { Button } from "@/components/ui/button";
66
import { TOPIC } from "@/constants/topic";
77
import { invalidateQueries } from "@/lib/tanstack";
88
import { useCreateTopic } from "@/lib/tanstack/mutation/topic";
9+
import { useStickerStore } from "@/lib/zustand/sticker-store";
910
import { useTopicStore } from "@/lib/zustand/topic-store";
1011
import { errorToast, infoToast } from "@/utils/toast";
1112
import { useOutsideClick } from "@repo/ui/hooks/use-outside-click";
@@ -17,13 +18,14 @@ import { Input } from "../../ui/input";
1718
export default function AddTopicModal() {
1819
const router = useRouter();
1920

20-
const topicStore = useTopicStore();
21+
const { setShowNewTopicModal, showNewTopicModal } = useTopicStore();
22+
const { setEditingSticker, editingSticker } = useStickerStore();
2123

2224
const { mutateAsync: createTopic, isPending } = useCreateTopic();
2325

2426
const onCloseModal = () => {
25-
topicStore.setShowNewTopicModal(false);
26-
topicStore.setEditingTopic(null);
27+
setShowNewTopicModal(false);
28+
setEditingSticker(null);
2729
};
2830

2931
const [dialogRef] = useOutsideClick<HTMLDivElement>(onCloseModal);
@@ -57,7 +59,7 @@ export default function AddTopicModal() {
5759
};
5860

5961
return (
60-
topicStore.showNewTopicModal && (
62+
showNewTopicModal && (
6163
<div
6264
role="dialog"
6365
className="fixed inset-0 z-[99999] flex items-center justify-center bg-black/50 transition-opacity duration-300"
@@ -67,7 +69,7 @@ export default function AddTopicModal() {
6769
<div className="mb-6">
6870
<h2 className="mb-2 text-xl font-semibold">새 토픽 생성</h2>
6971
<p className="text-muted-foreground">
70-
{topicStore.editingTopic ? "토픽을 수정하세요" : "새로운 토픽을 생성하고 관리하세요"}
72+
{editingSticker ? "토픽을 수정하세요" : "새로운 토픽을 생성하고 관리하세요"}
7173
</p>
7274
</div>
7375
<form onSubmit={onCreateTopic}>
@@ -76,7 +78,7 @@ export default function AddTopicModal() {
7678
<Input
7779
type="text"
7880
placeholder="토픽 제목을 입력하세요"
79-
defaultValue={topicStore.editingTopic?.title || ""}
81+
defaultValue={editingSticker?.title || ""}
8082
name="title"
8183
required
8284
/>
@@ -86,7 +88,7 @@ export default function AddTopicModal() {
8688
<textarea
8789
className="border-border bg-background resize-vertical min-h-[100px] w-full rounded-md border p-3"
8890
placeholder="토픽에 대한 설명을 입력하세요"
89-
defaultValue={topicStore.editingTopic?.content || ""}
91+
defaultValue={editingSticker?.content || ""}
9092
name="description"
9193
/>
9294
</div>
@@ -97,7 +99,7 @@ export default function AddTopicModal() {
9799
<Button type="submit" disabled={isPending}>
98100
{isPending ? (
99101
<Loader2 size={16} className="animate-spin" />
100-
) : topicStore.editingTopic ? (
102+
) : editingSticker ? (
101103
"수정"
102104
) : (
103105
"생성"

apps/web/src/components/topic/content-sticker.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { Button } from "../ui/button";
99
interface ContentStickerProps {
1010
item: CategoryContentDTO;
1111
isSelected: boolean;
12-
onSelect: (nodeId: number) => void;
12+
onSelect: (nodeId: string) => void;
1313
}
1414

1515
const contentType = {
@@ -66,7 +66,7 @@ export default function ContentSticker({ item, isSelected, onSelect }: ContentSt
6666
? "bg-primary text-white"
6767
: "bg-muted text-muted-foreground hover:bg-primary hover:text-white"
6868
)}
69-
onClick={() => onSelect(item.id)}
69+
onClick={() => onSelect(`content-${item.id}`)}
7070
aria-label={isSelected ? "선택 해제" : "선택"}
7171
>
7272
<Check size={16} />

apps/web/src/components/topic/custom-node.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import UserSticker from "./user-sticker";
2323
interface CustomNodeProps extends NodeProps {
2424
topicId: string;
2525
isSelected: boolean;
26-
onSelect: (nodeId: number) => void;
26+
onSelect: (nodeId: string) => void;
2727
}
2828

2929
interface NodeData {

apps/web/src/components/topic/edit-topic-sidebar/edit-topic-tooltip-list.tsx renamed to apps/web/src/components/topic/edit-sticker-sidebar/edit-sticker-tooltip-list.tsx

File renamed without changes.

apps/web/src/components/topic/edit-topic-sidebar/index.tsx renamed to apps/web/src/components/topic/edit-sticker-sidebar/index.tsx

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
useUpdateCustomSticker,
1414
} from "@/lib/tanstack/mutation/custom-sticker";
1515
import { useRemoveTopic, useUpdateTopic } from "@/lib/tanstack/mutation/topic";
16-
import { useTopicStore } from "@/lib/zustand/topic-store";
16+
import { useStickerStore } from "@/lib/zustand/sticker-store";
1717
import { containsMarkdown, markdownToHtml } from "@/utils/markdown";
1818
import { revalidatePath } from "@/utils/revalidate";
1919
import { errorToast, successToast } from "@/utils/toast";
@@ -28,7 +28,7 @@ import StarterKit from "@tiptap/starter-kit";
2828

2929
import { Loader2, Save, Trash2, X } from "lucide-react";
3030

31-
import EditTopicTooltipList from "./edit-topic-tooltip-list";
31+
import EditTopicTooltipList from "./edit-sticker-tooltip-list";
3232
import RemoveDialogContent from "../remove-dialog-content";
3333

3434
export default function EditTopicSidebar() {
@@ -49,19 +49,19 @@ export default function EditTopicSidebar() {
4949
const { mutateAsync: removeCustomSticker, isPending: isDeleteCustomStickerPending } =
5050
useRemoveCustomSticker();
5151

52-
const { setEditingTopic, setShowEditTopicSidebar, editingTopic, showEditTopicSidebar } =
53-
useTopicStore();
52+
const { setEditingSticker, setShowEditStickerSidebar, editingSticker, showEditStickerSidebar } =
53+
useStickerStore();
5454

5555
const buttonDisabled =
5656
isUpdatePending ||
5757
isDeletePending ||
5858
isUpdateCustomStickerPending ||
5959
isDeleteCustomStickerPending;
60-
const currentType = editingTopic?.type === "custom_sticker" ? "스티커" : "토픽";
60+
const currentType = editingSticker?.type === "custom_sticker" ? "스티커" : "토픽";
6161

6262
const onClose = () => {
63-
setEditingTopic(null);
64-
setShowEditTopicSidebar(false);
63+
setEditingSticker(null);
64+
setShowEditStickerSidebar(false);
6565
};
6666

6767
const onClickOutside = () => {
@@ -114,29 +114,29 @@ export default function EditTopicSidebar() {
114114
});
115115

116116
useEffect(() => {
117-
if (editingTopic && editor) {
118-
setTitle(editingTopic.title);
117+
if (editingSticker && editor) {
118+
setTitle(editingSticker.title);
119119

120120
// 마크다운이 포함되어 있으면 HTML로 변환
121-
if (editingTopic.content && containsMarkdown(editingTopic.content)) {
122-
const htmlContent = markdownToHtml(editingTopic.content);
121+
if (editingSticker.content && containsMarkdown(editingSticker.content)) {
122+
const htmlContent = markdownToHtml(editingSticker.content);
123123
editor.commands.setContent(htmlContent);
124124
} else {
125-
editor.commands.setContent(editingTopic.content || "");
125+
editor.commands.setContent(editingSticker.content || "");
126126
}
127127
}
128-
}, [editingTopic, editor]);
128+
}, [editingSticker, editor]);
129129

130130
const onSave = async () => {
131-
if (!editingTopic || !editor) return errorToast(`${currentType} 정보가 없어요.`);
131+
if (!editingSticker || !editor) return errorToast(`${currentType} 정보가 없어요.`);
132132

133133
try {
134134
const content = editor.getHTML();
135-
// TODO: editingTopic.type에 따라 API 요청 다르게
136-
if (editingTopic.type === "topic") {
135+
// TODO: editingSticker.type에 따라 API 요청 다르게
136+
if (editingSticker.type === "topic") {
137137
await updateTopic(
138138
{
139-
id: editingTopic.id,
139+
id: editingSticker.id,
140140
title,
141141
content,
142142
},
@@ -148,10 +148,10 @@ export default function EditTopicSidebar() {
148148
},
149149
}
150150
);
151-
} else if (editingTopic.type === "custom_sticker") {
151+
} else if (editingSticker.type === "custom_sticker") {
152152
await updateCustomSticker(
153153
{
154-
customStickerId: editingTopic.id,
154+
customStickerId: editingSticker.id,
155155
title,
156156
content,
157157
},
@@ -170,13 +170,13 @@ export default function EditTopicSidebar() {
170170
};
171171

172172
const onCloseSidebar = () => {
173-
setEditingTopic(null);
174-
setShowEditTopicSidebar(false);
173+
setEditingSticker(null);
174+
setShowEditStickerSidebar(false);
175175
onClose();
176176
};
177177

178178
const onDelete = async (id: number) => {
179-
if (editingTopic?.type === "topic") {
179+
if (editingSticker?.type === "topic") {
180180
await removeTopic(id, {
181181
onSuccess: () => {
182182
successToast("토픽이 성공적으로 삭제되었어요.");
@@ -189,7 +189,7 @@ export default function EditTopicSidebar() {
189189
errorToast("토픽 삭제에 실패했어요.");
190190
},
191191
});
192-
} else if (editingTopic?.type === "custom_sticker") {
192+
} else if (editingSticker?.type === "custom_sticker") {
193193
await removeCustomSticker(id, {
194194
onSuccess: () => {
195195
successToast("스티커가 성공적으로 삭제되었어요.");
@@ -204,7 +204,7 @@ export default function EditTopicSidebar() {
204204
};
205205

206206
return (
207-
<Sidebar isOpen={showEditTopicSidebar} onClose={onClickOutside}>
207+
<Sidebar isOpen={showEditStickerSidebar} onClose={onClickOutside}>
208208
<div className="flex h-full flex-col">
209209
{/* 헤더 */}
210210
<div className="flex items-center justify-between border-b p-6">
@@ -266,7 +266,7 @@ export default function EditTopicSidebar() {
266266
</DialogTrigger>
267267
</Button>
268268
<RemoveDialogContent
269-
id={editingTopic?.id || null}
269+
id={editingSticker?.id || null}
270270
setIsDeleteModalOpen={setIsDeleteModalOpen}
271271
onDelete={onDelete}
272272
/>

apps/web/src/components/topic/remove-content-button.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,24 @@ import { Button } from "../ui/button";
99

1010
interface RemoveContentButtonProps {
1111
topicId: string;
12-
selectedNodeIds: number[];
13-
setSelectedNodeIds: React.Dispatch<React.SetStateAction<number[]>>;
12+
selectedNodeIds: string[];
13+
setSelectedNodeIds: React.Dispatch<React.SetStateAction<string[]>>;
1414
}
1515

1616
export default function RemoveContentButton({
1717
topicId,
1818
selectedNodeIds,
1919
setSelectedNodeIds,
2020
}: RemoveContentButtonProps) {
21+
const contentIds = selectedNodeIds.map((id) => Number(id.split("-")[1]));
22+
2123
const { mutateAsync, isPending } = useRemoveTopicContentById();
2224

2325
const onRemoveContent = async () => {
2426
await mutateAsync(
2527
{
2628
topicId,
27-
contentIds: selectedNodeIds,
29+
contentIds,
2830
},
2931
{
3032
onSuccess: () => {

apps/web/src/components/topic/summarize-dialog.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { TOPIC } from "@/constants/topic";
44
import { invalidateQueries } from "@/lib/tanstack";
55
import { useSummarizeTopicContent } from "@/lib/tanstack/mutation/custom-sticker";
66
import { useGetAiModels } from "@/lib/tanstack/query/custom-sticker";
7-
import { useTopicStore } from "@/lib/zustand/topic-store";
7+
import { useStickerStore } from "@/lib/zustand/sticker-store";
88
import { AIModelDTO } from "@/models/custom-sticker";
99
import { zodResolver } from "@hookform/resolvers/zod";
1010
import {
@@ -25,7 +25,7 @@ import { Button } from "../ui/button";
2525

2626
interface SummarizeDialogProps {
2727
topicId: string;
28-
selectedNodeIds: number[];
28+
selectedNodeIds: string[];
2929
}
3030

3131
const DEFAULT_VALUES = {
@@ -37,7 +37,7 @@ const DEFAULT_VALUES = {
3737
function SummarizeDialogContent({ topicId, selectedNodeIds }: SummarizeDialogProps) {
3838
const [isModelDropdownOpen, setIsModelDropdownOpen] = useState(false);
3939

40-
const { setEditingTopic, setShowEditTopicSidebar } = useTopicStore();
40+
const { setEditingSticker, setShowEditStickerSidebar } = useStickerStore();
4141

4242
const [dropdownRef] = useOutsideClick<HTMLDivElement>(() => {
4343
setIsModelDropdownOpen(false);
@@ -52,6 +52,7 @@ function SummarizeDialogContent({ topicId, selectedNodeIds }: SummarizeDialogPro
5252
defaultValues: DEFAULT_VALUES,
5353
});
5454

55+
const selectedContentIds = selectedNodeIds.map((id) => Number(id.split("-")[1]));
5556
const watchedModel = watch("modelName");
5657

5758
const onModelSelect = (e: React.MouseEvent<HTMLButtonElement>, model: AIModelDTO) => {
@@ -70,19 +71,19 @@ function SummarizeDialogContent({ topicId, selectedNodeIds }: SummarizeDialogPro
7071
await mutateAsync(
7172
{
7273
topicId,
73-
selectedContentIds: selectedNodeIds,
74+
selectedContentIds,
7475
requirements: data.prompt,
7576
modelAlias: data.alias,
7677
},
7778
{
7879
onSuccess: (data) => {
7980
invalidateQueries([TOPIC.GET_TOPIC_BY_ID, topicId]);
80-
setEditingTopic({
81+
setEditingSticker({
8182
...data.result,
8283
content: data.result.draftMd,
8384
type: "custom_sticker",
8485
});
85-
setShowEditTopicSidebar(true);
86+
setShowEditStickerSidebar(true);
8687
close();
8788
},
8889
onError: (error) => {

apps/web/src/components/topic/topic-sticker.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useTopicStore } from "@/lib/zustand/topic-store";
1+
import { useStickerStore } from "@/lib/zustand/sticker-store";
22
import type { TopicDTO } from "@/models/topic";
33
import { Dialog, DialogTrigger } from "@repo/ui/components/dialog";
44

@@ -8,14 +8,14 @@ import RemoveTopicDialog from "./remove-topic-dialog";
88
import { Button } from "../ui/button";
99

1010
export default function TopicSticker({ item }: { item: TopicDTO }) {
11-
const { setEditingTopic, setShowEditTopicSidebar } = useTopicStore();
11+
const { setEditingSticker, setShowEditStickerSidebar } = useStickerStore();
1212

1313
const onEditTopic = () => {
14-
setEditingTopic({
14+
setEditingSticker({
1515
...item,
1616
type: "topic",
1717
});
18-
setShowEditTopicSidebar(true);
18+
setShowEditStickerSidebar(true);
1919
};
2020

2121
return (

apps/web/src/components/topic/user-sticker.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useTopicStore } from "@/lib/zustand/topic-store";
1+
import { useStickerStore } from "@/lib/zustand/sticker-store";
22
import type { TopicDTO } from "@/models/topic";
33
import { containsMarkdown, markdownToHtml } from "@/utils/markdown";
44
import { Dialog, DialogTrigger } from "@repo/ui/components/dialog";
@@ -9,14 +9,14 @@ import RemoveUserStickerDialog from "./remove-user-sticker-dialog";
99
import { Button } from "../ui/button";
1010

1111
export default function UserSticker({ item }: { item: TopicDTO }) {
12-
const { setEditingTopic, setShowEditTopicSidebar } = useTopicStore();
12+
const { setEditingSticker, setShowEditStickerSidebar } = useStickerStore();
1313

1414
const onEditTopic = () => {
15-
setEditingTopic({
15+
setEditingSticker({
1616
...item,
1717
type: "custom_sticker",
1818
});
19-
setShowEditTopicSidebar(true);
19+
setShowEditStickerSidebar(true);
2020
};
2121

2222
// 마크다운이 포함되어 있으면 HTML로 변환
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import type { TopicDTO } from "@/models/topic";
2+
import { StickerType } from "@/types/topic";
3+
4+
import { create } from "zustand";
5+
6+
interface EditingSticker extends TopicDTO {
7+
type: StickerType;
8+
}
9+
10+
interface StickerStore {
11+
showEditStickerSidebar: boolean;
12+
editingSticker: EditingSticker | null;
13+
setEditingSticker: (sticker: EditingSticker | null) => void;
14+
setShowEditStickerSidebar: (show: boolean) => void;
15+
}
16+
17+
export const useStickerStore = create<StickerStore>((set) => ({
18+
showEditStickerSidebar: false,
19+
setShowEditStickerSidebar: (show: boolean) => {
20+
set({ showEditStickerSidebar: show });
21+
},
22+
23+
editingSticker: null,
24+
setEditingSticker: (sticker: EditingSticker | null) => {
25+
set({ editingSticker: sticker });
26+
},
27+
}));

0 commit comments

Comments
 (0)