diff --git a/app/(afterLogin)/mypage/MypageActivity.tsx b/app/(afterLogin)/mypage/MypageActivity.tsx
new file mode 100644
index 0000000..d16a297
--- /dev/null
+++ b/app/(afterLogin)/mypage/MypageActivity.tsx
@@ -0,0 +1,125 @@
+"use client";
+
+import { useRouter, useSearchParams } from "next/navigation";
+
+import { LikedPrompt, MyPrompt } from "@/app/types/type";
+import {
+ LikedArticleCard,
+ MyArticleCard,
+} from "@/components/mypage/articleCard";
+import { toasts } from "@/components/shared/toast";
+import { cn } from "@/lib/utils";
+
+export default function MypageActivitySection() {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const activeSub = searchParams.get("sub") || "liked";
+
+ const handleSubTabChange = (sub: "liked" | "posted") => {
+ const params = new URLSearchParams(searchParams.toString());
+ params.set("sub", sub);
+ router.push(`/mypage?${params.toString()}`, { scroll: false });
+ };
+
+ const handleCopy = async (e: React.MouseEvent, content: string) => {
+ e.stopPropagation(); // 카드의 onClick이 실행되지 않도록 차단
+ try {
+ await navigator.clipboard.writeText(content);
+ toasts.success("프롬프트가 클립보드에 복사되었습니다!");
+ } catch {
+ alert("복사에 실패했습니다.");
+ }
+ };
+
+ const handleCardClick = (id: number) => {
+ router.push(`/prompts/${id}`);
+ };
+
+ // 실제 API 데이터 구조에 맞춘 임시 데이터
+ // 1. 좋아요 한 프롬프트 데이터
+ const mockLikedPrompts = [
+ {
+ promptId: 1024,
+ title: "좋아요 - 자소서를 위한 GPT 프롬프트",
+ description: "이 프롬프트는 좋아요 탭에서만 보입니다.",
+ isLiked: true,
+ },
+ {
+ promptId: 1025,
+ title: "좋아요 - 면접 대비 프롬프트",
+ description: "상세한 설명이 들어가는 영역입니다.",
+ isLiked: true,
+ },
+ ];
+
+ // 2. 내가 게시한 프롬프트 데이터 (createdAt 포함)
+ const mockMyPrompts = [
+ {
+ promptId: 2048,
+ title: "게시글 - 나만의 비밀 프롬프트",
+ description: "내가 직접 작성해서 게시한 프롬프트입니다.",
+ createdAt: "2026-02-18T10:00:00", // n시간 전/일 전 테스트용
+ },
+ {
+ promptId: 2049,
+ title: "게시글 - 효율적인 코딩 프롬프트",
+ description: "코딩 효율을 200% 높여주는 마법의 문장들.",
+ createdAt: "2026-01-20T13:50:00",
+ },
+ ];
+ const currentList = activeSub === "liked" ? mockLikedPrompts : mockMyPrompts;
+
+ return (
+
+ {/* 서브 탭 메뉴 */}
+
+
+
+
+
+ {/* 리스트 영역 */}
+
+ {activeSub === "liked"
+ ? (mockLikedPrompts as LikedPrompt[]).map((prompt) => (
+ handleCopy(e, prompt.description)}
+ onClick={() => handleCardClick(prompt.promptId)}
+ />
+ ))
+ : (mockMyPrompts as MyPrompt[]).map((prompt) => (
+ handleCardClick(prompt.promptId)}
+ />
+ ))}
+
+
+ );
+}
diff --git a/app/(afterLogin)/mypage/MypageLeftSection.tsx b/app/(afterLogin)/mypage/MypageLeftSection.tsx
new file mode 100644
index 0000000..ca4802c
--- /dev/null
+++ b/app/(afterLogin)/mypage/MypageLeftSection.tsx
@@ -0,0 +1,99 @@
+"use client";
+
+import { useRouter } from "next/navigation";
+import { useEffect, useState } from "react";
+
+import UserProfile from "@/components/mypage/user-profile";
+import { BaseButton } from "@/components/shared/button";
+
+interface UserData {
+ nickname: string;
+ email: string;
+ profileImage: string;
+ introduction: string;
+ provider: "KAKAO" | "NAVER";
+}
+
+export default function MypageLeftSection() {
+ const router = useRouter();
+ const [userData, setUserData] = useState(null);
+ const [isLoading, setIsLoading] = useState(true);
+
+ useEffect(() => {
+ const loadUserData = async () => {
+ try {
+ //나중에 다른것들처럼 mock api생성 후 연결 예정
+ // 테스트용 더미 데이터
+ setUserData({
+ nickname: "개구리",
+ email: "frog@example.com",
+ profileImage: "",
+ introduction: "반갑습니다!",
+ provider: "KAKAO",
+ });
+ } catch (error) {
+ console.error("유저 정보 로드 실패:", error);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ loadUserData();
+ }, []);
+
+ const handleLogout = async () => {
+ if (confirm("로그아웃 하시겠습니까?")) {
+ try {
+ //로그아웃 호출
+
+ alert("로그아웃 되었습니다.");
+ router.push("/"); //로그아웃되고 어느 페이지로 이동?
+ router.refresh();
+ } catch (error) {
+ console.error("Logout failed:", error);
+ }
+ }
+ };
+
+ if (isLoading) return 로딩 중...
;
+ if (!userData) return 유저 정보가 없습니다.
;
+
+ const handleWithdraw = async () => {
+ const isConfirmed = confirm(
+ "정말로 탈퇴하시겠습니까?\n탈퇴 시 모든 데이터가 삭제되며 복구할 수 없습니다."
+ );
+
+ if (isConfirmed) {
+ try {
+ // 탈퇴 기능 호출
+ alert("회원 탈퇴가 완료되었습니다.");
+ router.push("/");
+ } catch (error) {
+ alert("탈퇴 처리 중 오류가 발생했습니다.");
+ }
+ }
+ };
+ return (
+
+
+
+
+ 로그아웃
+
+
+
+
+ );
+}
diff --git a/app/(afterLogin)/mypage/MypageRightSection.tsx b/app/(afterLogin)/mypage/MypageRightSection.tsx
new file mode 100644
index 0000000..ba57694
--- /dev/null
+++ b/app/(afterLogin)/mypage/MypageRightSection.tsx
@@ -0,0 +1,221 @@
+"use client";
+
+import Link from "next/link";
+import { useState } from "react";
+
+import {
+ EDUCATION_OPTIONS,
+ JobType,
+ STATE_VALUES,
+} from "@/app/(beforeLogin)/(auth)/constant";
+import { StatusSelect } from "@/app/(beforeLogin)/(auth)/signup/component/StatusSelect";
+import { TargetJobsSelect } from "@/app/(beforeLogin)/(auth)/signup/component/TargetJobsSelect";
+import { useSignupStore } from "@/app/store/signUpStore";
+import UserExperience from "@/components/mypage/user-experience";
+import UserKeyword from "@/components/mypage/user-keyword";
+import { BaseButton } from "@/components/shared/button";
+import { BaseCheckBox } from "@/components/shared/checkbox";
+import { BaseInput } from "@/components/shared/inputs";
+import { SelectBox } from "@/components/shared/select-box";
+
+export default function MypageRightSection() {
+ const [otherInput, setOtherInput] = useState("");
+ const [experiences, setExperiences] = useState([]);
+ const [keywords, setKeywords] = useState([]);
+
+ // 개인정보 마케팅 동의 상태 (예시)
+ const [marketingAgree, setMarketingAgree] = useState(false);
+
+ const {
+ targetJobs,
+ setTargetJobs,
+ currentState,
+ career,
+ educationLevel,
+ updateField,
+ } = useSignupStore();
+
+ // 직무 클릭 핸들러
+ const handleJobClick = (option: string) => {
+ const castedOption = option as JobType;
+ if (targetJobs.includes(castedOption)) {
+ setTargetJobs(targetJobs.filter((j) => j !== castedOption));
+ } else {
+ setTargetJobs([...targetJobs, castedOption]);
+ }
+ };
+
+ // 섹션별 저장 핸들러
+ const handleSaveEmployment = async () => {
+ const payload = {
+ currentState:
+ currentState === STATE_VALUES.OTHER ? otherInput : currentState,
+ targetJobs,
+ educationLevel,
+ career,
+ };
+ console.log("취업/경력 저장:", payload);
+ alert("취업/경력 정보가 저장되었습니다.");
+ };
+
+ const handleSaveProfile = async () => {
+ const payload = { experiences, keywords };
+ console.log("프로필 저장:", payload);
+ alert("프로필 정보가 저장되었습니다.");
+ };
+
+ const handleSavePrivacy = async () => {
+ console.log("개인정보 설정 저장:", { marketingAgree });
+ alert("개인정보 설정이 변경되었습니다.");
+ };
+
+ const handleCancel = () => {
+ if (confirm("변경사항이 저장되지 않을 수 있습니다. 취소하시겠습니까?")) {
+ window.location.reload();
+ }
+ };
+
+ return (
+
+ {/* 1. 취업/경력 섹션 */}
+
+
{"취업/경력"}
+
{
+ updateField("currentState", val);
+ if (val !== STATE_VALUES.OTHER) setOtherInput("");
+ }}
+ onOtherChange={setOtherInput}
+ />
+
+
+
+
+ updateField("educationLevel", val)}
+ selectOptions={EDUCATION_OPTIONS}
+ />
+
+
+
+ {
+ const val = e.target.value.replace(/[^0-9]/g, "");
+ updateField("career", val === "" ? 0 : Number(val));
+ }}
+ />
+
+
+
+
+ 취소
+
+
+ 변경사항 저장
+
+
+
+
+ {/* 2. 자기소개 프로필 섹션 */}
+
+
+
{"자기소개 프로필"}
+
+ 자소서 미리보기에 활용될 정보입니다
+
+
+
+
+
+
+ 취소
+
+
+ 변경사항 저장
+
+
+
+
+ {/* 3. 개인정보 관리 섹션 */}
+
+
+
{"개인정보 관리"}
+
+ 현재 적용 중인 개인정보 수집 및 이용 동의 현황입니다.
+
+
+
+
+ setMarketingAgree(!!checked)}
+ />
+
+ 보기
+
+
+
+
+
+ 취소
+
+
+ 변경사항 저장
+
+
+
+
+ );
+}
diff --git a/app/(afterLogin)/mypage/layout.tsx b/app/(afterLogin)/mypage/layout.tsx
new file mode 100644
index 0000000..710287f
--- /dev/null
+++ b/app/(afterLogin)/mypage/layout.tsx
@@ -0,0 +1,14 @@
+import { Header } from "@/components/header/header";
+
+export default function DashboardLayout({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ return (
+
+ );
+}
diff --git a/app/(afterLogin)/mypage/page.tsx b/app/(afterLogin)/mypage/page.tsx
index 06752e9..07c5e02 100644
--- a/app/(afterLogin)/mypage/page.tsx
+++ b/app/(afterLogin)/mypage/page.tsx
@@ -1,5 +1,77 @@
+"use client";
+import { useRouter, useSearchParams } from "next/navigation";
+
+import { BaseButton } from "@/components/shared/button";
+import { PageTitleGroup } from "@/components/shared/page-title-group";
+import { cn } from "@/lib/utils";
+
+import MypageActivitySection from "./MypageActivity";
+import MypageLeftSection from "./MypageLeftSection";
+import MypageRightSection from "./MypageRightSection";
+
export default function MyPage() {
- return MyPage
;
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ // URL에서 tab 파라미터를 가져옴 (기본값: profile)
+ const activeTab =
+ (searchParams.get("tab") as "profile" | "activity") || "profile";
+
+ // 탭 변경 시 URL 업데이트
+ const handleTabChange = (tab: "profile" | "activity") => {
+ router.push(`/mypage?tab=${tab}`, { scroll: false });
+ };
+
+ return (
+
+
+
+
+
+ handleTabChange("profile")}
+ className={cn(
+ "px-4 py-2.5 min-w-[197px] shadow-sm transition-colors",
+ activeTab === "profile"
+ ? "bg-frog-600"
+ : "bg-gray-0 text-gray-700 border border-gray-100"
+ )}
+ >
+ 프로필 설정
+
+ handleTabChange("activity")}
+ className={cn(
+ "px-4 py-2.5 min-w-[197px] shadow-sm transition-colors",
+ activeTab === "activity"
+ ? "bg-frog-600"
+ : "bg-gray-0 text-gray-700 border border-gray-100 hover:text-gray-0"
+ )}
+ >
+ 내 활동
+
+
+
+
+
+ {/* 왼쪽: 유저 프로필 */}
+
+
+ {/* 오른쪽: 정보수정 */}
+
+ {activeTab === "profile" ? (
+
+ ) : (
+
+ )}
+
+
+
+ );
}
/**
diff --git a/app/(beforeLogin)/(auth)/signup/component/Detail.tsx b/app/(beforeLogin)/(auth)/signup/component/Detail.tsx
index a8dc608..06ff7f6 100644
--- a/app/(beforeLogin)/(auth)/signup/component/Detail.tsx
+++ b/app/(beforeLogin)/(auth)/signup/component/Detail.tsx
@@ -86,6 +86,7 @@ export default function Detail() {
/>
{
@@ -95,7 +96,11 @@ export default function Detail() {
onOtherChange={setOtherInput}
/>
-
+
diff --git a/app/(beforeLogin)/(auth)/signup/component/StatusSelect.tsx b/app/(beforeLogin)/(auth)/signup/component/StatusSelect.tsx
index 8b9409b..c68bc04 100644
--- a/app/(beforeLogin)/(auth)/signup/component/StatusSelect.tsx
+++ b/app/(beforeLogin)/(auth)/signup/component/StatusSelect.tsx
@@ -3,6 +3,7 @@ import { BaseInput } from "@/components/shared/inputs";
import { STATE_OPTIONS, STATE_VALUES, StateType } from "../../constant";
interface StatusSelectProps {
+ label: string;
value: StateType | "";
otherValue: string;
onSelect: (status: StateType) => void;
@@ -10,6 +11,7 @@ interface StatusSelectProps {
}
export const StatusSelect = ({
+ label,
value,
otherValue,
onSelect,
@@ -17,7 +19,7 @@ export const StatusSelect = ({
}: StatusSelectProps) => {
return (
- 현재 상태를 선택해주세요.
+ {label}
{STATE_OPTIONS.map((option) => (