+
+
{
) : (
-
-
-
+
+
+
+
+
+
+
+
)
}
/>
-
-
- 환영합니다!
-
- >
+
+
+
+
경험의 경로를 알려주다
+
+
+
+
+ 흩어진 경험을 하나의 흐름으로,
+
+ 취업 준비의 모든 과정을 한 곳에서
+
+
+
+
+
+
+ 에피소드 시작하기
+
+
+
+
+
+
+
+
+
+
+
+ {/*
*/}
+
+
+
마인드맵
+
+ 경험을 시각적으로 구조화하고 관리하세요.
+
+ 노드로 연결하며 개요 구조를 체계적으로 정리할 수 있어요.
+
+
+
+ -
+
+
+ 한줄 카테고리/클러스터 구조화
+
+
+ -
+
+
+ 실시간 협업 및 공유 기능
+
+
+
+
+
+
+
+ 마인드맵 시작하기
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
기술문제 셀프진단
+
+ 기술 자소서 문항을 기준으로 빈틈을 점검하세요.
+
+ 부족한 역량을 발견하고, 에피소드를 준비할 수 있어요.
+
+
+
+ -
+
+
+ 주요 직무별 자소서 문항 분석
+
+
+ -
+
+
+ 기술 역량을 드러내는 질문 추천
+
+
+
+
+
+
+
+ 기술문제 셀프진단 하기
+
+
+
+
+ {/*
+
*/}
+
+
+
+
+
+
+
+
+
+ {/*
*/}
+
+
+
에피소드 보관함
+
+ 모든 경험을 STAR 기반으로 체계적으로 정리해요.
+
+ 자기소개서에 필요한 에피소드를 완성할 수 있어요.
+
+
+
+ -
+
+
+ STAR 형식으로 에피소드 작성
+
+
+ -
+
+
+ 마인드맵 기반 에피소드 연결
+
+
+ -
+
+ 태그 기반 검색 및 정리
+
+
+
+
+
+
+ 에피소드 보관함 가기
+
+
+
+
+
+
+
+
+
+
+
);
};
diff --git a/frontend/src/features/mindmap/components/MindmapCard.tsx b/frontend/src/features/mindmap/components/MindmapCard.tsx
index d6b4b3edc..9484187aa 100644
--- a/frontend/src/features/mindmap/components/MindmapCard.tsx
+++ b/frontend/src/features/mindmap/components/MindmapCard.tsx
@@ -2,7 +2,7 @@ import { useRef, useState } from "react";
import { useNavigate } from "react-router";
import { useDeleteMindmap } from "@/features/mindmap/hooks/useDeleteMindmap";
-import { useUpdateMindmapFavorite } from "@/features/mindmap/hooks/useUpdateMindmapFavorite"; // 훅 import
+import { useUpdateMindmapFavorite } from "@/features/mindmap/hooks/useUpdateMindmapFavorite";
import { useUpdateMindmapName } from "@/features/mindmap/hooks/useUpdateMindmapName";
import { MindmapItem, MindmapType } from "@/features/mindmap/types/mindmap";
import Button from "@/shared/components/button/Button";
@@ -21,15 +21,29 @@ import { getRelativeTime } from "@/utils/get_relative_time";
type Props = {
data: MindmapItem;
type?: MindmapType;
+
+ interaction?: "navigate" | "select";
+ selected?: boolean;
+ onSelect?: (mindmapId: string) => void;
+
+ className?: string;
};
-const MindmapCard = ({ data, type = "PUBLIC" }: Props) => {
+const MindmapCard = ({ data, type = "PUBLIC", interaction = "navigate", selected, onSelect, className }: Props) => {
const { mutate: deleteMindmap } = useDeleteMindmap();
const { mutate: updateMindmapName } = useUpdateMindmapName();
const { mutate: updateMindmapFavorite } = useUpdateMindmapFavorite();
const navigate = useNavigate();
+ const handleCardClick = () => {
+ if (interaction === "select") {
+ onSelect?.(data.mindmapId);
+ return;
+ }
+ navigate(linkTo.mindmap.detail(data.mindmapId));
+ };
+
const handleDelete = (e: React.MouseEvent) => {
e.stopPropagation();
if (window.confirm("정말 이 마인드맵을 삭제하시겠습니까?")) {
@@ -54,7 +68,6 @@ const MindmapCard = ({ data, type = "PUBLIC" }: Props) => {
if (value.length <= 20) {
setEditName(value);
} else {
- // 20자가 넘어가면 잘라냄 (붙여넣기 대응)
setEditName(value.slice(0, 20));
}
};
@@ -97,10 +110,12 @@ const MindmapCard = ({ data, type = "PUBLIC" }: Props) => {
return (
{
- navigate(linkTo.mindmap.detail(data.mindmapId));
- }}
+ className={cn(
+ "min-h-50 overflow-hidden w-full",
+ selected && "outline-primary outline-2 shadow-md",
+ className,
+ )}
+ onClick={handleCardClick}
header={
{isEditing ? (
@@ -163,32 +178,14 @@ const MindmapCard = ({ data, type = "PUBLIC" }: Props) => {
}
>
)}
}
- bottomContents={
-
- {/* {displayTags.map((tag, index) => (
-
- {tag}
-
- ))}
- {hiddenTagCount > 0 && (
-
- +{hiddenTagCount}
-
- )} */}
-
- }
+ bottomContents={
{getRelativeTime(data.updatedAt)}
diff --git a/frontend/src/features/mindmap/components/MindmapCategoryStep.tsx b/frontend/src/features/mindmap/components/MindmapCategoryStep.tsx
new file mode 100644
index 000000000..b74142de6
--- /dev/null
+++ b/frontend/src/features/mindmap/components/MindmapCategoryStep.tsx
@@ -0,0 +1,89 @@
+import { useCreateMindmap } from "@/features/mindmap/hooks/useCreateMindmap";
+import { ACTIVITY_CATEGORIES, ActivityCategory } from "@/features/mindmap/types/mindmap";
+import { CreateMindmapFunnel } from "@/features/mindmap/types/mindmap_funnel";
+import BottomSticky from "@/shared/components/bottom_sticky/BottomSticky";
+import Button from "@/shared/components/button/Button";
+import { EmojiCard } from "@/shared/components/emoji_card/EmojiCard";
+import Top from "@/shared/components/top/Top";
+import { FunnelInstance } from "@/shared/hooks/useFunnel";
+import { linkTo } from "@/shared/utils/route";
+
+type CategoryStepFunnel = Extract
, { step: "CATEGORY" }>;
+
+export function MindmapCategoryStep({ funnel }: { funnel: CategoryStepFunnel }) {
+ const { mutate: createMindmap, isPending } = useCreateMindmap();
+
+ const selected = funnel.context.categories ?? [];
+
+ const toggle = (id: ActivityCategory) => {
+ funnel.history.setContext((prev) => {
+ const prevSelected = prev.categories ?? [];
+ const next = prevSelected.includes(id) ? prevSelected.filter((x) => x !== id) : [...prevSelected, id];
+ return { ...prev, categories: next };
+ });
+ };
+
+ const canSubmit = selected.length > 0;
+
+ const handleSubmit = () => {
+ createMindmap(
+ {
+ isShared: false,
+ title: "새로운 마인드맵",
+ },
+ {
+ onSuccess: (data) => {
+ funnel.exit(linkTo.mindmap.detail(data.mindmap.mindmapId), { replace: false });
+ },
+ onError: (e) => {
+ console.error("마인드맵 생성에 실패했습니다.", e);
+ },
+ },
+ );
+ };
+
+ return (
+ <>
+
+
+ 마인드맵으로 정리할
활동 카테고리를 선택하세요.
+
+ }
+ lower={
+
+ 사용 목적에 따라 알맞는 마인드맵 유형을 선택해 주세요.
+
+ }
+ className="mb-12"
+ />
+
+
+ {ACTIVITY_CATEGORIES.map((c) => (
+ toggle(c.id)}
+ />
+ ))}
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/frontend/src/features/mindmap/components/MindmapTypeCard.tsx b/frontend/src/features/mindmap/components/MindmapTypeCard.tsx
new file mode 100644
index 000000000..0b7d0a01b
--- /dev/null
+++ b/frontend/src/features/mindmap/components/MindmapTypeCard.tsx
@@ -0,0 +1,44 @@
+import Card from "@/shared/components/card/Card";
+import Icon, { IconName } from "@/shared/components/icon/Icon";
+import { cn } from "@/utils/cn";
+
+type Props = {
+ icon: IconName;
+ title: string;
+ description: string;
+ isSelected: boolean;
+ onClick: () => void;
+};
+
+const MindmapTypeCard = ({ icon, title, description, isSelected, onClick }: Props) => {
+ return (
+
+ {isSelected && (
+
+
+
+ )}
+
+
+ {title}
+
+ }
+ contents={
+