diff --git a/src/components/icons/IconEmptyOutlined.tsx b/src/components/icons/IconEmptyOutlined.tsx
new file mode 100644
index 0000000..041e016
--- /dev/null
+++ b/src/components/icons/IconEmptyOutlined.tsx
@@ -0,0 +1,15 @@
+const IconEmptyOutlined = () => {
+ return (
+
+ );
+};
+
+export default IconEmptyOutlined;
diff --git a/src/components/icons/IconWarningOutlined.tsx b/src/components/icons/IconWarningOutlined.tsx
new file mode 100644
index 0000000..21516bd
--- /dev/null
+++ b/src/components/icons/IconWarningOutlined.tsx
@@ -0,0 +1,15 @@
+const IconWarningOutlined = () => {
+ return (
+
+ );
+};
+
+export default IconWarningOutlined;
diff --git a/src/components/inputs/TextInput/TextInput.tsx b/src/components/inputs/TextInput/TextInput.tsx
index 33318fb..49763fc 100644
--- a/src/components/inputs/TextInput/TextInput.tsx
+++ b/src/components/inputs/TextInput/TextInput.tsx
@@ -75,6 +75,11 @@ const TextInput: React.FC
= ({
}
}, [enteredValue, status, onTextChange]);
+ useEffect(() => {
+ // 비동기 API 호출로 인한 value 변경 시에만 실행
+ setEnteredValue(value);
+ }, [value]);
+
return (
{label && {label}}
diff --git a/src/components/navbar/Navbar.tsx b/src/components/navbar/Navbar.tsx
index ebf03ff..83d7e00 100644
--- a/src/components/navbar/Navbar.tsx
+++ b/src/components/navbar/Navbar.tsx
@@ -2,9 +2,7 @@ import styled from "@emotion/styled";
import { LAYOUT_MARGIN } from "constant/layoutMargin";
import { NAVBAR_HEIGHT } from "constant/navbarHeight";
-interface Props {}
-
-const Navbar = ({}: Props) => {
+const Navbar = () => {
return Navbar;
};
diff --git a/src/constant/link.ts b/src/constant/link.ts
new file mode 100644
index 0000000..51d19e7
--- /dev/null
+++ b/src/constant/link.ts
@@ -0,0 +1,22 @@
+/**
+ * 이 파일에서는 링크 경로를 관리합니다.
+ * autoComplete 및 검색에 도움이 되도록 `LINK_` 로 시작하는 이름을 사용합니다.
+ */
+
+// 메인 페이지 경로
+export const LINK_MAIN_PAGE = "/";
+
+// 로그인 페이지 경로
+export const LINK_LOGIN_PAGE = "/login";
+
+// 마이 페이지
+export const LINK_MYPAGE = "/mypage";
+
+// 내 정보 수정 페이지
+export const LINK_MYPAGE_EDIT = "/mypage/edit";
+
+// 계정 탈퇴 페이지
+export const LINK_ACCOUNT_DELETE = "/mypage/delete";
+
+// 계정 탈퇴 성공 시 이동할 경로
+export const LINK_ACCOUNT_DELETE_SUCCESS = "/mypage/delete/success";
diff --git a/src/feature/.gitkeep b/src/feature/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/src/feature/mypage/common/constants/genderLookupTable.ts b/src/feature/mypage/common/constants/genderLookupTable.ts
new file mode 100644
index 0000000..db93284
--- /dev/null
+++ b/src/feature/mypage/common/constants/genderLookupTable.ts
@@ -0,0 +1,5 @@
+export const GENDER_LOOKUP_TABLE = {
+ M: "남성",
+ F: "여성",
+ U: "선택 안함",
+};
diff --git a/src/feature/mypage/common/mockup/MockupMypage.tsx b/src/feature/mypage/common/mockup/MockupMypage.tsx
new file mode 100644
index 0000000..e3c3e31
--- /dev/null
+++ b/src/feature/mypage/common/mockup/MockupMypage.tsx
@@ -0,0 +1,8 @@
+import { TUser } from "feature/mypage/mypage.edit/types/TMypageFormValues";
+
+export const MOCKUP_MYPAGE_INITIAL_VALUES: TUser = {
+ nickname: "홍길동",
+ introduction: "안녕하세요. 저는 홍길동입니다.",
+ birthYear: "1990",
+ gender: "M",
+};
diff --git a/src/feature/mypage/mypage.delete/components/MypageDeleteAlert.tsx b/src/feature/mypage/mypage.delete/components/MypageDeleteAlert.tsx
new file mode 100644
index 0000000..7c7454e
--- /dev/null
+++ b/src/feature/mypage/mypage.delete/components/MypageDeleteAlert.tsx
@@ -0,0 +1,51 @@
+import styled from "@emotion/styled";
+import IconWarningOutlined from "components/icons/IconWarningOutlined";
+
+const MypageDeleteAlert = () => {
+ return (
+
+
+
+ 회원 탈퇴 시, 아래의 정보가 삭제됩니다.
+
+ - 회원 정보
+ - 내가 속한 단체의 소속상태
+
+
+ 단, 내가 생성한 맛집, 투표, 모임 정보 등은 유지되며, 생성자의 정보에 '탈퇴한 유저'
+ 라고 표시됩니다.{" "}
+
+
+ );
+};
+
+export default MypageDeleteAlert;
+
+const EmotionWrapper = styled.div`
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ .warning-title {
+ font-size: 16px;
+ font-weight: 700;
+ margin-top: 32px;
+ margin-bottom: 24px;
+ }
+
+ .deleted-item {
+ margin-bottom: 4px;
+
+ &:before {
+ content: "•";
+ margin-right: 8px;
+ }
+ }
+
+ .warning-disclaimer {
+ font-size: 12px;
+ margin-top: 32px;
+ color: ${({ theme }) => theme.color.gray400};
+ line-height: 1.5;
+ }
+`;
diff --git a/src/feature/mypage/mypage.delete/components/MypageDeleteConfirmForm.tsx b/src/feature/mypage/mypage.delete/components/MypageDeleteConfirmForm.tsx
new file mode 100644
index 0000000..334d370
--- /dev/null
+++ b/src/feature/mypage/mypage.delete/components/MypageDeleteConfirmForm.tsx
@@ -0,0 +1,58 @@
+import styled from "@emotion/styled";
+import Button from "components/button/Button";
+import TextInput from "components/inputs/TextInput/TextInput";
+import { LINK_ACCOUNT_DELETE_SUCCESS } from "constant/link";
+import { validateDeleteConfirmMessage } from "feature/mypage/mypage.delete/functions/validateDeleteConfirmMessage";
+import { TTextInputItem } from "feature/mypage/mypage.delete/types/TTextInputItem";
+import { useRouter } from "next/router";
+import { useCallback, useState } from "react";
+
+const MypageDeleteConfirmForm = () => {
+ const { push } = useRouter();
+
+ const [confirmFormValues, setConfirmFormValues] = useState({
+ value: "",
+ isValid: false,
+ });
+
+ const handleChangeConfirmValue = useCallback((value: string, isValid: boolean) => {
+ setConfirmFormValues({
+ value,
+ isValid,
+ });
+ }, []);
+
+ const handleSubmitDeleteAccount = () => {
+ // TODO: Modal, toast 등으로 피드백 처리
+ if (!confirmFormValues.isValid) {
+ alert("탈퇴 메시지를 확인해주세요");
+ return;
+ }
+ // TODO: API 연동 , 여기서 실제 탈퇴 API 호출 후 성공 시 아래 링크로 이동
+ push(LINK_ACCOUNT_DELETE_SUCCESS);
+ };
+
+ return (
+
+
+
+
+ );
+};
+
+export default MypageDeleteConfirmForm;
+
+const EmotionWrapper = styled.div`
+ margin-top: 64px;
+
+ button {
+ margin-top: 32px;
+ }
+`;
diff --git a/src/feature/mypage/mypage.delete/functions/validateDeleteConfirmMessage.ts b/src/feature/mypage/mypage.delete/functions/validateDeleteConfirmMessage.ts
new file mode 100644
index 0000000..8261789
--- /dev/null
+++ b/src/feature/mypage/mypage.delete/functions/validateDeleteConfirmMessage.ts
@@ -0,0 +1,7 @@
+export const validateDeleteConfirmMessage = {
+ condition: (value: string): boolean => {
+ if (value !== "탈퇴") return false;
+ return true;
+ },
+ messageOnError: "'탈퇴' 를 입력해주세요.",
+};
diff --git a/src/feature/mypage/mypage.delete/types/TTextInputItem.tsx b/src/feature/mypage/mypage.delete/types/TTextInputItem.tsx
new file mode 100644
index 0000000..18c9dac
--- /dev/null
+++ b/src/feature/mypage/mypage.delete/types/TTextInputItem.tsx
@@ -0,0 +1,5 @@
+// TODO: 추후 공통 폴더로 이동하면 좋을 것 같음.
+export type TTextInputItem = {
+ value: string;
+ isValid: boolean;
+};
diff --git a/src/feature/mypage/mypage.delete/views/ViewMypageDelete.tsx b/src/feature/mypage/mypage.delete/views/ViewMypageDelete.tsx
new file mode 100644
index 0000000..40687d0
--- /dev/null
+++ b/src/feature/mypage/mypage.delete/views/ViewMypageDelete.tsx
@@ -0,0 +1,16 @@
+import styled from "@emotion/styled";
+import MypageDeleteAlert from "feature/mypage/mypage.delete/components/MypageDeleteAlert";
+import MypageDeleteConfirmForm from "feature/mypage/mypage.delete/components/MypageDeleteConfirmForm";
+
+const ViewMypageDelete = () => {
+ return (
+
+
+
+
+ );
+};
+
+export default ViewMypageDelete;
+
+const EmotionWrapper = styled.div``;
diff --git a/src/feature/mypage/mypage.delete/views/ViewMypageDeleteSuccess.tsx b/src/feature/mypage/mypage.delete/views/ViewMypageDeleteSuccess.tsx
new file mode 100644
index 0000000..21fbc47
--- /dev/null
+++ b/src/feature/mypage/mypage.delete/views/ViewMypageDeleteSuccess.tsx
@@ -0,0 +1,36 @@
+import styled from "@emotion/styled";
+import Button from "components/button/Button";
+import { LINK_MAIN_PAGE } from "constant/link";
+import Link from "next/link";
+
+const ViewMypageDeleteSuccess = () => {
+ return (
+
+ 회원탈퇴가 완료되었습니다.
+
+
+
+
+ );
+};
+
+export default ViewMypageDeleteSuccess;
+
+const EmotionWrapper = styled.div`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+
+ width: 100%;
+ margin-top: 200px;
+
+ h1 {
+ font-size: 20px;
+ font-weight: 700;
+ }
+
+ button {
+ margin-top: 100px;
+ }
+`;
diff --git a/src/feature/mypage/mypage.edit/constants/GenderDropdownValueList.ts b/src/feature/mypage/mypage.edit/constants/GenderDropdownValueList.ts
new file mode 100644
index 0000000..aa1813c
--- /dev/null
+++ b/src/feature/mypage/mypage.edit/constants/GenderDropdownValueList.ts
@@ -0,0 +1,14 @@
+export const GENDER_DROPDOWN_VALUE_LIST = [
+ {
+ value: "F",
+ label: "여성",
+ },
+ {
+ value: "M",
+ label: "남성",
+ },
+ {
+ value: "U",
+ label: "선택안함",
+ },
+];
diff --git a/src/feature/mypage/mypage.edit/constants/birthYearDropdownValues.ts b/src/feature/mypage/mypage.edit/constants/birthYearDropdownValues.ts
new file mode 100644
index 0000000..cb83523
--- /dev/null
+++ b/src/feature/mypage/mypage.edit/constants/birthYearDropdownValues.ts
@@ -0,0 +1,8 @@
+// create an array of birth year dropdown values from 1900 to current year - 10
+export const BIRTH_YEAR_DROPDOWN_VALUE_LIST = Array.from(
+ { length: new Date().getFullYear() - 1900 - 10 },
+ (_, i) => ({
+ value: String(new Date().getFullYear() - i - 10),
+ label: String(new Date().getFullYear() - i - 10),
+ })
+);
diff --git a/src/feature/mypage/mypage.edit/types/TMypageFormValues.ts b/src/feature/mypage/mypage.edit/types/TMypageFormValues.ts
new file mode 100644
index 0000000..452237d
--- /dev/null
+++ b/src/feature/mypage/mypage.edit/types/TMypageFormValues.ts
@@ -0,0 +1,20 @@
+type TGender = "M" | "F" | "U";
+type TFormValueItem = {
+ value: string;
+ isValid: boolean;
+};
+
+// TODO: API 응답 형식에 따라 달라질 수 있음
+export type TUser = {
+ nickname: string;
+ introduction: string;
+ birthYear: string;
+ gender: TGender;
+};
+
+export type TMypageFormValues = {
+ nickname: TFormValueItem;
+ introduction: TFormValueItem;
+ birthYear: TFormValueItem;
+ gender: TFormValueItem;
+};
diff --git a/src/feature/mypage/mypage.edit/views/ViewMypageEdit.tsx b/src/feature/mypage/mypage.edit/views/ViewMypageEdit.tsx
new file mode 100644
index 0000000..4bc3b94
--- /dev/null
+++ b/src/feature/mypage/mypage.edit/views/ViewMypageEdit.tsx
@@ -0,0 +1,122 @@
+import styled from "@emotion/styled";
+import Button from "components/button/Button";
+import Dropdown from "components/dropdown/Dropdown";
+import TextInput from "components/inputs/TextInput/TextInput";
+import { GENDER_DROPDOWN_VALUE_LIST } from "feature/mypage/mypage.edit/constants/GenderDropdownValueList";
+import { MOCKUP_MYPAGE_INITIAL_VALUES } from "feature/mypage/common/mockup/MockupMypage";
+import { TMypageFormValues } from "feature/mypage/mypage.edit/types/TMypageFormValues";
+import Link from "next/link";
+import { useCallback, useEffect, useState } from "react";
+import { BIRTH_YEAR_DROPDOWN_VALUE_LIST } from "feature/mypage/mypage.edit/constants/birthYearDropdownValues";
+import { LINK_ACCOUNT_DELETE } from "constant/link";
+
+const { Option } = Dropdown;
+
+const ViewMypageEdit = () => {
+ const [formValues, setFormValues] = useState({
+ nickname: { value: "", isValid: false },
+ introduction: { value: "", isValid: false },
+ birthYear: { value: "", isValid: false },
+ gender: { value: "", isValid: false },
+ });
+
+ const handleChangeInput = useCallback(
+ (name: string) => (value: string, isValid: boolean) => {
+ setFormValues((prev) => ({
+ ...prev, // TODO: ... 연산자가 1레벨까지만 복사한다는 것을 기억하자.
+ [name]: { value, isValid },
+ }));
+ },
+ []
+ );
+
+ const handleChangeNickname = useCallback(handleChangeInput("nickname"), []);
+ const handleChangeDescription = useCallback(handleChangeInput("introduction"), []);
+
+ const { nickname, introduction, gender, birthYear } = formValues;
+
+ // TODO: 서버 데이터 받아오는 작업 모킹
+ useEffect(() => {
+ const nextFormValues = {} as TMypageFormValues;
+
+ Object.keys(MOCKUP_MYPAGE_INITIAL_VALUES).forEach((key) => {
+ const value = MOCKUP_MYPAGE_INITIAL_VALUES[key as keyof TMypageFormValues];
+
+ nextFormValues[key as keyof TMypageFormValues] = {
+ value,
+ isValid: true,
+ };
+ });
+ setFormValues(nextFormValues);
+ }, []);
+
+ return (
+
+
+
+
+
+ {BIRTH_YEAR_DROPDOWN_VALUE_LIST.map(({ value, label }) => (
+
+ ))}
+
+ {/* TODO => placeholder 가 적용되지 않는 문제 핵결*/}
+
+ {GENDER_DROPDOWN_VALUE_LIST.map(({ value, label }) => (
+
+ ))}
+
+
+
+
+ 탈퇴하기
+
+
+ );
+};
+
+export default ViewMypageEdit;
+
+const EmotionWrapper = styled.div`
+ .input-container {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ row-gap: 32px;
+ }
+
+ .button-save {
+ margin-top: 32px;
+ }
+
+ .button-remove-account {
+ float: right;
+ font-size: 12px;
+ margin-top: 100px;
+ color: ${({ theme }) => theme.color.danger400};
+ }
+`;
diff --git a/src/feature/mypage/mypage.main/components/MyPageActionButtons.tsx b/src/feature/mypage/mypage.main/components/MyPageActionButtons.tsx
new file mode 100644
index 0000000..2e6a541
--- /dev/null
+++ b/src/feature/mypage/mypage.main/components/MyPageActionButtons.tsx
@@ -0,0 +1,35 @@
+import Link from "next/link";
+import styled from "@emotion/styled";
+import Button from "components/button/Button";
+import { LINK_MAIN_PAGE, LINK_MYPAGE_EDIT } from "constant/link";
+
+const MyPageActionButtons = () => {
+ // TODO: API 연동 후 로그아웃 시 API 바로 호출되도록 수정
+ const LOGOUT_REDIRECT_URL = LINK_MAIN_PAGE;
+
+ return (
+
+
+
+
+
+
+
+
+ );
+};
+
+export default MyPageActionButtons;
+
+const EmotionWrapper = styled.div`
+ float: right;
+ display: flex;
+ align-items: flex-end;
+ flex-direction: column;
+
+ .button-logout {
+ color: ${({ theme }) => theme.color.danger600};
+ }
+`;
diff --git a/src/feature/mypage/mypage.main/components/MyPageBasicInfo.tsx b/src/feature/mypage/mypage.main/components/MyPageBasicInfo.tsx
new file mode 100644
index 0000000..c50c1f6
--- /dev/null
+++ b/src/feature/mypage/mypage.main/components/MyPageBasicInfo.tsx
@@ -0,0 +1,38 @@
+import styled from "@emotion/styled";
+import dayjs from "dayjs";
+import { GENDER_LOOKUP_TABLE } from "feature/mypage/common/constants/genderLookupTable";
+import { MOCKUP_MYPAGE_INITIAL_VALUES } from "feature/mypage/common/mockup/MockupMypage";
+import MyPageInfoItem from "feature/mypage/mypage.main/components/typography/MyPageInfoItem";
+import MyPageSectionTitle from "feature/mypage/mypage.main/components/typography/MyPageSectionTitle";
+
+const MyPageBasicInfo = () => {
+ const userInfo = MOCKUP_MYPAGE_INITIAL_VALUES;
+ const { birthYear, gender } = userInfo;
+
+ const age = dayjs().year() - Number(birthYear);
+ const ageText = `${age}세`;
+
+ const genderText = GENDER_LOOKUP_TABLE[gender] ?? "입력하지 않음";
+
+ return (
+
+ 내 정보
+
+
+
+
+
+ );
+};
+
+export default MyPageBasicInfo;
+
+const EmotionWrapper = styled.div`
+ margin-bottom: 48px;
+
+ .item-container {
+ display: flex;
+ flex-direction: column;
+ row-gap: 12px;
+ }
+`;
diff --git a/src/feature/mypage/mypage.main/components/MyPageOrganizationInfo.tsx b/src/feature/mypage/mypage.main/components/MyPageOrganizationInfo.tsx
new file mode 100644
index 0000000..a4ef789
--- /dev/null
+++ b/src/feature/mypage/mypage.main/components/MyPageOrganizationInfo.tsx
@@ -0,0 +1,21 @@
+import styled from "@emotion/styled";
+import EmptyOrganizationCTA from "feature/mypage/mypage.main/components/empty/EmptyOrganizationCTA";
+import MyPageSectionTitle from "feature/mypage/mypage.main/components/typography/MyPageSectionTitle";
+
+const MyPageOrganizationInfo = () => {
+ const orgList = [];
+ const isEmpty = orgList?.length === 0;
+
+ return (
+
+ 내가 속한 단체 정보
+ {isEmpty && }
+
+ );
+};
+
+export default MyPageOrganizationInfo;
+
+const EmotionWrapper = styled.div`
+ margin-bottom: 64px;
+`;
diff --git a/src/feature/mypage/mypage.main/components/MyPageProfileInfo.tsx b/src/feature/mypage/mypage.main/components/MyPageProfileInfo.tsx
new file mode 100644
index 0000000..861d0ee
--- /dev/null
+++ b/src/feature/mypage/mypage.main/components/MyPageProfileInfo.tsx
@@ -0,0 +1,44 @@
+import styled from "@emotion/styled";
+import ProfileImage from "components/profileImage/ProfileImage";
+import { MOCKUP_MYPAGE_INITIAL_VALUES } from "feature/mypage/common/mockup/MockupMypage";
+
+const MyPageProfileInfo = () => {
+ const userInfo = MOCKUP_MYPAGE_INITIAL_VALUES;
+ const { nickname, introduction } = userInfo;
+
+ return (
+
+
+
+
+
{nickname}
+
{introduction}
+
+
+
+ );
+};
+
+export default MyPageProfileInfo;
+
+const EmotionWrapper = styled.div`
+ margin-bottom: 32px;
+
+ .profile-section {
+ display: flex;
+ column-gap: 16px;
+ align-items: center;
+
+ .user-name {
+ font-size: 16px;
+ font-weight: 700;
+ color: ${({ theme }) => theme.color.black};
+ margin-bottom: 8px;
+ }
+
+ .user-description {
+ font-size: 12px;
+ color: ${({ theme }) => theme.color.gray400};
+ }
+ }
+`;
diff --git a/src/feature/mypage/mypage.main/components/empty/EmptyOrganizationCTA.tsx b/src/feature/mypage/mypage.main/components/empty/EmptyOrganizationCTA.tsx
new file mode 100644
index 0000000..34a6824
--- /dev/null
+++ b/src/feature/mypage/mypage.main/components/empty/EmptyOrganizationCTA.tsx
@@ -0,0 +1,35 @@
+import styled from "@emotion/styled";
+import Button from "components/button/Button";
+import IconEmptyOutlined from "components/icons/IconEmptyOutlined";
+
+const EmptyOrganizationCTA = () => {
+ return (
+
+
+ 가입된 단체가 없네요. 🥲
+ 가입할 단체를 한번 찾아볼까요?
+
+
+ );
+};
+
+export default EmptyOrganizationCTA;
+
+const EmotionWrapper = styled.div`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+
+ .cta-first-line {
+ margin-top: 24px;
+ }
+
+ .cta-second-line {
+ margin-top: 8px;
+ }
+
+ button {
+ margin-top: 36px;
+ }
+`;
diff --git a/src/feature/mypage/mypage.main/components/typography/MyPageInfoItem.tsx b/src/feature/mypage/mypage.main/components/typography/MyPageInfoItem.tsx
new file mode 100644
index 0000000..eef7312
--- /dev/null
+++ b/src/feature/mypage/mypage.main/components/typography/MyPageInfoItem.tsx
@@ -0,0 +1,35 @@
+import styled from "@emotion/styled";
+
+interface Props {
+ label: string;
+ value: string;
+}
+
+const MyPageInfoItem = ({ label, value }: Props) => {
+ return (
+
+ {label}
+ {value}
+
+ );
+};
+
+export default MyPageInfoItem;
+
+const EmotionWrapper = styled.div`
+ display: flex;
+ align-items: center;
+ column-gap: 16px;
+
+ .label {
+ font-size: 16px;
+ color: ${({ theme }) => theme.color.gray400};
+ min-width: 60px;
+ }
+
+ .value {
+ font-size: 16px;
+ font-weight: 700;
+ color: ${({ theme }) => theme.color.black};
+ }
+`;
diff --git a/src/feature/mypage/mypage.main/components/typography/MyPageSectionTitle.tsx b/src/feature/mypage/mypage.main/components/typography/MyPageSectionTitle.tsx
new file mode 100644
index 0000000..7d74391
--- /dev/null
+++ b/src/feature/mypage/mypage.main/components/typography/MyPageSectionTitle.tsx
@@ -0,0 +1,18 @@
+import styled from "@emotion/styled";
+import { ReactNode } from "react";
+
+interface Props {
+ children?: ReactNode;
+}
+
+const MyPageSectionTitle = ({ children }: Props) => {
+ return {children};
+};
+
+export default MyPageSectionTitle;
+
+const EmotionWrapper = styled.h2`
+ font-size: 12px;
+ color: ${({ theme }) => theme.color.gray500};
+ margin-bottom: 16px;
+`;
diff --git a/src/feature/mypage/mypage.main/views/ViewMypage.tsx b/src/feature/mypage/mypage.main/views/ViewMypage.tsx
new file mode 100644
index 0000000..472d1c2
--- /dev/null
+++ b/src/feature/mypage/mypage.main/views/ViewMypage.tsx
@@ -0,0 +1,17 @@
+import MyPageActionButtons from "feature/mypage/mypage.main/components/MyPageActionButtons";
+import MyPageBasicInfo from "feature/mypage/mypage.main/components/MyPageBasicInfo";
+import MyPageOrganizationInfo from "feature/mypage/mypage.main/components/MyPageOrganizationInfo";
+import MyPageProfileInfo from "feature/mypage/mypage.main/components/MyPageProfileInfo";
+
+const ViewMypage = () => {
+ return (
+ <>
+
+
+
+
+ >
+ );
+};
+
+export default ViewMypage;
diff --git a/src/pages/_error.tsx b/src/pages/_error.tsx
index 5997381..e01c7e3 100644
--- a/src/pages/_error.tsx
+++ b/src/pages/_error.tsx
@@ -1,6 +1,7 @@
import Link from "next/link";
import styled from "@emotion/styled";
import { NextPageContext } from "next";
+import { LINK_MAIN_PAGE } from "constant/link";
interface Props {
statusCode?: number;
@@ -13,7 +14,7 @@ const CustomError = ({ statusCode, title }: Props) => {
{statusCode}
{title}
- 홈으로
+ 홈으로
);
};
diff --git a/src/pages/login/index.tsx b/src/pages/login/index.tsx
index 31aab46..9fd5fd2 100644
--- a/src/pages/login/index.tsx
+++ b/src/pages/login/index.tsx
@@ -1,5 +1,6 @@
import styled from "@emotion/styled";
import PageMarker from "components/pageMarker/PageMarker";
+import { LINK_MAIN_PAGE } from "constant/link";
import { GetServerSideProps } from "next";
const PageLogin = () => {
@@ -25,7 +26,7 @@ export const getServerSideProps: GetServerSideProps = async ({ req, res, query }
const isLoggedIn = req.cookies.accessToken;
if (isLoggedIn) {
- res.writeHead(302, { Location: "/" });
+ res.writeHead(302, { Location: LINK_MAIN_PAGE });
res.end();
}
diff --git a/src/pages/mypage/delete/index.tsx b/src/pages/mypage/delete/index.tsx
new file mode 100644
index 0000000..e2e6564
--- /dev/null
+++ b/src/pages/mypage/delete/index.tsx
@@ -0,0 +1,30 @@
+import { LINK_MAIN_PAGE, LINK_MYPAGE } from "constant/link";
+import ViewMypageDelete from "feature/mypage/mypage.delete/views/ViewMypageDelete";
+import { GetServerSideProps } from "next";
+
+const PageMyPageDelete = () => {
+ return ;
+};
+
+export default PageMyPageDelete;
+
+export const getServerSideProps: GetServerSideProps = async ({ req, res, query }) => {
+ /**
+ * 로그인하지 않은 경우 메인 페이지로 이동
+ * 마이페이지로부터 유입되지 않은 경우 메인 페이지로 이동
+ */
+
+ const referer = req.headers.referer;
+ const isLoggedIn = true;
+ const isFromMyPage = referer?.includes(LINK_MYPAGE);
+ const shouldRedirect = !isLoggedIn || !isFromMyPage;
+
+ if (shouldRedirect) {
+ res.writeHead(302, { Location: LINK_MAIN_PAGE });
+ res.end();
+ }
+
+ return {
+ props: {},
+ };
+};
diff --git a/src/pages/mypage/delete/success.tsx b/src/pages/mypage/delete/success.tsx
new file mode 100644
index 0000000..b5472f9
--- /dev/null
+++ b/src/pages/mypage/delete/success.tsx
@@ -0,0 +1,30 @@
+import { LINK_ACCOUNT_DELETE, LINK_MAIN_PAGE } from "constant/link";
+import ViewMypageDeleteSuccess from "feature/mypage/mypage.delete/views/ViewMypageDeleteSuccess";
+import { GetServerSideProps } from "next";
+
+const PageMyPageDeleteSuccess = () => {
+ return ;
+};
+
+export default PageMyPageDeleteSuccess;
+
+export const getServerSideProps: GetServerSideProps = async ({ req, res, query }) => {
+ /**
+ * 로그인하지 않은 경우 메인 페이지로 이동
+ * 로그인 되어 있으나, 탈퇴 페이지로부터 유입되지 않은 경우 메인 페이지로 이동
+ */
+ const referer = req.headers.referer;
+ const isLoggedIn = false;
+ const isFromDeletePage = referer?.includes(LINK_ACCOUNT_DELETE);
+
+ const shouldRedirect = !isLoggedIn || !isFromDeletePage;
+
+ if (shouldRedirect) {
+ res.writeHead(302, { Location: LINK_MAIN_PAGE });
+ res.end();
+ }
+
+ return {
+ props: {},
+ };
+};
diff --git a/src/pages/mypage/edit.tsx b/src/pages/mypage/edit.tsx
new file mode 100644
index 0000000..2a6f6e3
--- /dev/null
+++ b/src/pages/mypage/edit.tsx
@@ -0,0 +1,25 @@
+import { GetServerSideProps } from "next";
+import ViewMyPageEdit from "feature/mypage/mypage.edit/views/ViewMypageEdit";
+import { LINK_LOGIN_PAGE } from "constant/link";
+
+const PageMyPageEdit = () => {
+ return ;
+};
+
+export default PageMyPageEdit;
+
+export const getServerSideProps: GetServerSideProps = async ({ req, res, query }) => {
+ /**
+ * 로그인하지 않은 경우 로그인 페이지로 이동
+ */
+ const isLoggedIn = true;
+
+ if (!isLoggedIn) {
+ res.writeHead(302, { Location: LINK_LOGIN_PAGE });
+ res.end();
+ }
+
+ return {
+ props: {},
+ };
+};
diff --git a/src/pages/mypage/index.tsx b/src/pages/mypage/index.tsx
new file mode 100644
index 0000000..2c92b43
--- /dev/null
+++ b/src/pages/mypage/index.tsx
@@ -0,0 +1,25 @@
+import { GetServerSideProps } from "next";
+import ViewMypage from "feature/mypage/mypage.main/views/ViewMypage";
+import { LINK_LOGIN_PAGE } from "constant/link";
+
+const PageMyPage = () => {
+ return ;
+};
+
+export default PageMyPage;
+
+export const getServerSideProps: GetServerSideProps = async ({ req, res, query }) => {
+ /**
+ * 로그인하지 않은 경우 로그인 페이지로 이동
+ */
+ const isLoggedIn = true;
+
+ if (!isLoggedIn) {
+ res.writeHead(302, { Location: LINK_LOGIN_PAGE });
+ res.end();
+ }
+
+ return {
+ props: {},
+ };
+};
diff --git a/src/pages/register/index.tsx b/src/pages/register/index.tsx
index c85f73d..0d8f138 100644
--- a/src/pages/register/index.tsx
+++ b/src/pages/register/index.tsx
@@ -1,5 +1,6 @@
import styled from "@emotion/styled";
import PageMarker from "components/pageMarker/PageMarker";
+import { LINK_MAIN_PAGE } from "constant/link";
import { GetServerSideProps } from "next";
const PageRegister = () => {
@@ -24,7 +25,7 @@ export const getServerSideProps: GetServerSideProps = async ({ req, res, query }
const hasAuthenticated = true;
if (isNicknameAlreadySet || !hasAuthenticated) {
- res.writeHead(302, { Location: "/" });
+ res.writeHead(302, { Location: LINK_MAIN_PAGE });
res.end();
}
diff --git a/src/pages/register/success.tsx b/src/pages/register/success.tsx
index e0eaec5..61fb66e 100644
--- a/src/pages/register/success.tsx
+++ b/src/pages/register/success.tsx
@@ -1,5 +1,6 @@
import styled from "@emotion/styled";
import PageMarker from "components/pageMarker/PageMarker";
+import { LINK_MAIN_PAGE } from "constant/link";
import { GetServerSideProps } from "next";
const PageRegisterSuccess = () => {
@@ -24,7 +25,7 @@ export const getServerSideProps: GetServerSideProps = async ({ req, res, query }
const hasUserAlreadyViewedSuccessPage = false;
if (hasUserAlreadyViewedSuccessPage) {
- res.writeHead(302, { Location: "/" });
+ res.writeHead(302, { Location: LINK_MAIN_PAGE });
res.end();
}