diff --git a/src/app/application/ScorePageContent.tsx b/src/app/application/ScorePageContent.tsx new file mode 100644 index 00000000..9a92cf99 --- /dev/null +++ b/src/app/application/ScorePageContent.tsx @@ -0,0 +1,172 @@ +"use client"; + +import { useRouter } from "next/navigation"; +import { useEffect, useRef, useState } from "react"; + +import { getApplicationListApi, getCompetitorsApplicationListApi } from "@/services/application"; + +import CloudSpinnerPage from "@/components/loading/CloudSpinnerPage"; +import ConfirmCancelModal from "@/components/modal/ConfirmCancelModal"; +import ButtonTab from "@/components/ui/ButtonTab"; +import Tab from "@/components/ui/Tab"; + +import ScoreSearchBar from "./ScoreSearchBar"; +import ScoreSearchField from "./ScoreSearchField"; +import ScoreSheets from "./ScoreSheets"; + +import { REGIONS_KO } from "@/constants/university"; +import { ApplicationListResponse } from "@/types/application"; +import { RegionKo } from "@/types/university"; + +const PREFERENCE_CHOICE: string[] = ["1순위", "2순위", "3순위"]; + +const ScorePageContent = () => { + const router = useRouter(); + const [loading, setLoading] = useState(true); + // 검색 + const [searchActive, setSearchActive] = useState(false); // 검색 창 활성화 여부 + const searchRef = useRef(null); + // 점수 데이터 + const [scoreData, setScoreData] = useState({ + firstChoice: [], + secondChoice: [], + thirdChoice: [], + }); + const [filteredScoreData, setFilteredScoreData] = useState({ + firstChoice: [], + secondChoice: [], + thirdChoice: [], + }); + const [preference, setPreference] = useState<"1순위" | "2순위" | "3순위">("1순위"); + const [filter, setFilter] = useState(""); + + const [showNeedApply, setShowNeedApply] = useState(false); + + useEffect(() => { + const fetchData = async () => { + try { + if (true) { + const scoreResponse = await getCompetitorsApplicationListApi(); + + const scoreResponseData = scoreResponse.data; + scoreResponseData.firstChoice.sort((a, b) => b.applicants.length - a.applicants.length); + scoreResponseData.secondChoice.sort((a, b) => b.applicants.length - a.applicants.length); + scoreResponseData.thirdChoice.sort((a, b) => b.applicants.length - a.applicants.length); + setScoreData(scoreResponseData); + setFilteredScoreData(scoreResponseData); + } + } catch (err) { + if (err.response) { + if (err.response.status === 404) { + setShowNeedApply(true); + } else if (err.response.status === 401 || err.response.status === 403) { + alert("로그인이 필요합니다"); + document.location.href = "/login"; + } else { + alert(err.response.data?.message); + } + } else { + console.error("Error", err.message); + } + } finally { + setLoading(false); + } + }; + fetchData(); + }, []); + + const handleSearch = (event: React.FormEvent) => { + event.preventDefault(); + const keyWord = searchRef.current?.value || ""; + setFilter(""); + setFilteredScoreData( + keyWord + ? { + firstChoice: scoreData.firstChoice.filter((sheet) => sheet.koreanName.includes(keyWord)), + secondChoice: scoreData.secondChoice.filter((sheet) => sheet.koreanName.includes(keyWord)), + thirdChoice: scoreData.thirdChoice.filter((sheet) => sheet.koreanName.includes(keyWord)), + } + : scoreData, + ); + setSearchActive(false); + }; + + const handleSearchField = (keyWord: string) => { + if (searchRef.current) { + searchRef.current.value = keyWord; + } + }; + + const handleSearchClick = () => { + setSearchActive(true); + }; + + const hotKeyWords = ["RMIT", "오스트라바", "칼스루에", "그라츠", "추오", "프라하", "보라스", "빈", "메모리얼"]; + + useEffect(() => { + if (filter) { + setFilteredScoreData({ + firstChoice: scoreData.firstChoice.filter((sheet) => sheet.region === filter), + secondChoice: scoreData.secondChoice.filter((sheet) => sheet.region === filter), + thirdChoice: scoreData.thirdChoice.filter((sheet) => sheet.region === filter), + }); + } else { + setFilteredScoreData(scoreData); + } + }, [filter, scoreData]); + + if (loading) { + return ; + } + + const getScoreSheet = () => { + if (preference === "1순위") { + return filteredScoreData.firstChoice; + } + if (preference === "2순위") { + return filteredScoreData.secondChoice; + } + if (preference === "3순위") { + return filteredScoreData.thirdChoice; + } + return []; + }; + + if (searchActive) { + return ( + <> + {}} /> + { + handleSearchField(e); + }} + /> + + ); + } + + return ( + <> + + + + + { + router.push("/"); + }} + handleConfirm={() => { + router.push("/application/apply"); + }} + title="" + content={"점수 공유현황을 확인하려면 지원절차를\n진행해주세요."} + cancelText="확인" + approveText="학교 지원하기" + /> + + ); +}; + +export default ScorePageContent; diff --git a/src/app/application/apply/ApplyPageContent.tsx b/src/app/application/apply/ApplyPageContent.tsx new file mode 100644 index 00000000..5586aa6d --- /dev/null +++ b/src/app/application/apply/ApplyPageContent.tsx @@ -0,0 +1,178 @@ +"use client"; + +import { useRouter } from "next/navigation"; +import { useEffect, useState } from "react"; + +import { postApplicationApi } from "@/services/application"; +import { getMyGpaScoreApi, getMyLanguageTestScoreApi } from "@/services/score"; +import { getUniversityListPublicApi } from "@/services/university"; + +import TopDetailNavigation from "@/components/layout/TopDetailNavigation"; +import ProgressBar from "@/components/ui/ProgressBar"; + +import ConfirmStep from "./ConfirmStep"; +import DoneStep from "./DoneStep"; +import GpaStep from "./GpaStep"; +import LanguageStep from "./LanguageStep"; +import UniversityStep from "./UniversityStep"; + +import { GpaScore, LanguageTestScore } from "@/types/score"; +import { ListUniversity } from "@/types/university"; + +const ApplyPageContent = () => { + const router = useRouter(); + const [step, setStep] = useState(1); + + const [languageTestScoreList, setLanguageTestScoreList] = useState([]); + const [gpaScoreList, setGpaScoreList] = useState([]); + const [universityList, setUniversityList] = useState([]); + + const [curLanguageTestScore, setCurLanguageTestScore] = useState(null); + const [curGpaScore, setCurGpaScore] = useState(null); + const [curUniversityList, setCurUniversityList] = useState([]); + + const [isSubmitting, setIsSubmitting] = useState(false); + + useEffect(() => { + const fetchAll = async () => { + try { + const [gpaRes, languageRes, universityRes] = await Promise.all([ + getMyGpaScoreApi(), + getMyLanguageTestScoreApi(), + getUniversityListPublicApi(), + ]); + setGpaScoreList( + gpaRes.data.gpaScoreStatusResponseList.filter((score: GpaScore) => score.verifyStatus === "APPROVED"), + ); + setLanguageTestScoreList( + languageRes.data.languageTestScoreStatusResponseList.filter( + (score: LanguageTestScore) => score.verifyStatus === "APPROVED", + ), + ); + + // 대학명을 지역/나라, 대학명 가나다 순으로 정렬합니다 + const sortedUniversityList = [...universityRes.data].sort((a, b) => { + // 1) region 비교 + const regionCompare = a.region.localeCompare(b.region); + if (regionCompare !== 0) return regionCompare; + + // 2) country 비교 + const countryCompare = a.country.localeCompare(b.country); + if (countryCompare !== 0) return countryCompare; + + // 3) 같은 region, country라면 대학명을 비교(가나다 순) + return a.koreanName.localeCompare(b.koreanName); + }); + setUniversityList(sortedUniversityList); + } catch (err) { + if (err.response) { + console.error("Axios response error", err.response); + if (err.response.status === 401 || err.response.status === 403) { + alert("로그인이 필요합니다"); + document.location.href = "/login"; + } else { + alert(err.response.data?.message); + } + } else { + console.error("Error", err.message); + alert(err.message); + } + } + }; + fetchAll(); + }, []); + + // 다음 스텝으로 넘어가기 + const goNextStep = () => setStep((prev) => prev + 1); + // 이전 스텝으로 돌아가기 + const goPrevStep = () => { + if (step === 1) { + router.back(); + } + setStep((prev) => prev - 1); + }; + + const handleSubmit = async () => { + if (!curGpaScore) { + alert("GPA를 선택해주세요."); + return; + } + + if (!curLanguageTestScore) { + alert("어학성적을 선택해주세요."); + return; + } + + if (curUniversityList.length === 0 || curUniversityList[0] === 0) { + alert("대학교를 선택해주세요."); + return; + } + + if (isSubmitting) return; + setIsSubmitting(true); // TODO: 현재 임시 submit 처리, 이후에 통합 처리 추가 + try { + await postApplicationApi({ + gpaScoreId: curGpaScore, + languageTestScoreId: curLanguageTestScore, + universityChoiceRequest: { + firstChoiceUniversityId: curUniversityList[0] || null, + secondChoiceUniversityId: curUniversityList[1] || null, + thirdChoiceUniversityId: curUniversityList[2] || null, + }, + }); + setStep(99); + } catch (err) { + alert(err.response.data.message); + } finally { + setIsSubmitting(false); + } + }; + + return ( + <> + +
+ {(step === 1 || step === 2 || step === 3) && } +
+ {step === 1 && ( + + )} + {step === 2 && ( + + )} + {step === 3 && ( + + )} + {step === 4 && ( + score.id === curLanguageTestScore)} + gpaScore={gpaScoreList.find((score) => score.id === curGpaScore)} + universityList={ + curUniversityList + .map((id) => universityList.find((university) => university.id === id)) + .filter(Boolean) as ListUniversity[] + } + onNext={handleSubmit} + /> + )} + {step === 99 && } + + ); +}; + +export default ApplyPageContent; diff --git a/src/app/application/apply/page.tsx b/src/app/application/apply/page.tsx index 5995ea32..64a1cfb2 100644 --- a/src/app/application/apply/page.tsx +++ b/src/app/application/apply/page.tsx @@ -1,176 +1,15 @@ -"use client"; +import { Metadata } from "next"; -import { useRouter } from "next/navigation"; -import { useEffect, useState } from "react"; +import ApplyPageContent from "./ApplyPageContent"; -import { postApplicationApi } from "@/services/application"; -import { getMyGpaScoreApi, getMyLanguageTestScoreApi } from "@/services/score"; -import { getUniversityListPublicApi } from "@/services/university"; - -import TopDetailNavigation from "@/components/layout/TopDetailNavigation"; -import ProgressBar from "@/components/ui/ProgressBar"; - -import ConfirmStep from "./ConfirmStep"; -import DoneStep from "./DoneStep"; -import GpaStep from "./GpaStep"; -import LanguageStep from "./LanguageStep"; -import UniversityStep from "./UniversityStep"; - -import { GpaScore, LanguageTestScore } from "@/types/score"; -import { ListUniversity } from "@/types/university"; +export const metadata: Metadata = { + title: "지원하기", +}; const ApplyPage = () => { - const router = useRouter(); - const [step, setStep] = useState(1); - - const [languageTestScoreList, setLanguageTestScoreList] = useState([]); - const [gpaScoreList, setGpaScoreList] = useState([]); - const [universityList, setUniversityList] = useState([]); - - const [curLanguageTestScore, setCurLanguageTestScore] = useState(null); - const [curGpaScore, setCurGpaScore] = useState(null); - const [curUniversityList, setCurUniversityList] = useState([]); - - const [isSubmitting, setIsSubmitting] = useState(false); - - useEffect(() => { - const fetchAll = async () => { - try { - const [gpaRes, languageRes, universityRes] = await Promise.all([ - getMyGpaScoreApi(), - getMyLanguageTestScoreApi(), - getUniversityListPublicApi(), - ]); - setGpaScoreList( - gpaRes.data.gpaScoreStatusResponseList.filter((score: GpaScore) => score.verifyStatus === "APPROVED"), - ); - setLanguageTestScoreList( - languageRes.data.languageTestScoreStatusResponseList.filter( - (score: LanguageTestScore) => score.verifyStatus === "APPROVED", - ), - ); - - // 대학명을 지역/나라, 대학명 가나다 순으로 정렬합니다 - const sortedUniversityList = [...universityRes.data].sort((a, b) => { - // 1) region 비교 - const regionCompare = a.region.localeCompare(b.region); - if (regionCompare !== 0) return regionCompare; - - // 2) country 비교 - const countryCompare = a.country.localeCompare(b.country); - if (countryCompare !== 0) return countryCompare; - - // 3) 같은 region, country라면 대학명을 비교(가나다 순) - return a.koreanName.localeCompare(b.koreanName); - }); - setUniversityList(sortedUniversityList); - } catch (err) { - if (err.response) { - console.error("Axios response error", err.response); - if (err.response.status === 401 || err.response.status === 403) { - alert("로그인이 필요합니다"); - document.location.href = "/login"; - } else { - alert(err.response.data?.message); - } - } else { - console.error("Error", err.message); - alert(err.message); - } - } - }; - fetchAll(); - }, []); - - // 다음 스텝으로 넘어가기 - const goNextStep = () => setStep((prev) => prev + 1); - // 이전 스텝으로 돌아가기 - const goPrevStep = () => { - if (step === 1) { - router.back(); - } - setStep((prev) => prev - 1); - }; - - const handleSubmit = async () => { - if (!curGpaScore) { - alert("GPA를 선택해주세요."); - return; - } - - if (!curLanguageTestScore) { - alert("어학성적을 선택해주세요."); - return; - } - - if (curUniversityList.length === 0 || curUniversityList[0] === 0) { - alert("대학교를 선택해주세요."); - return; - } - - if (isSubmitting) return; - setIsSubmitting(true); // TODO: 현재 임시 submit 처리, 이후에 통합 처리 추가 - try { - await postApplicationApi({ - gpaScoreId: curGpaScore, - languageTestScoreId: curLanguageTestScore, - universityChoiceRequest: { - firstChoiceUniversityId: curUniversityList[0] || null, - secondChoiceUniversityId: curUniversityList[1] || null, - thirdChoiceUniversityId: curUniversityList[2] || null, - }, - }); - setStep(99); - } catch (err) { - alert(err.response.data.message); - } finally { - setIsSubmitting(false); - } - }; - return ( <> - -
- {(step === 1 || step === 2 || step === 3) && } -
- {step === 1 && ( - - )} - {step === 2 && ( - - )} - {step === 3 && ( - - )} - {step === 4 && ( - score.id === curLanguageTestScore)} - gpaScore={gpaScoreList.find((score) => score.id === curGpaScore)} - universityList={ - curUniversityList - .map((id) => universityList.find((university) => university.id === id)) - .filter(Boolean) as ListUniversity[] - } - onNext={handleSubmit} - /> - )} - {step === 99 && } + ); }; diff --git a/src/app/application/page.tsx b/src/app/application/page.tsx index 57206985..5d9f7a1d 100644 --- a/src/app/application/page.tsx +++ b/src/app/application/page.tsx @@ -1,173 +1,18 @@ -"use client"; - -import { useRouter } from "next/navigation"; -import { useEffect, useRef, useState } from "react"; - -import { getApplicationListApi, getCompetitorsApplicationListApi } from "@/services/application"; +import { Metadata } from "next"; import TopDetailNavigation from "@/components/layout/TopDetailNavigation"; -import CloudSpinnerPage from "@/components/loading/CloudSpinnerPage"; -import ConfirmCancelModal from "@/components/modal/ConfirmCancelModal"; -import ButtonTab from "@/components/ui/ButtonTab"; -import Tab from "@/components/ui/Tab"; -import ScoreSearchBar from "./ScoreSearchBar"; -import ScoreSearchField from "./ScoreSearchField"; -import ScoreSheets from "./ScoreSheets"; +import ScorePageContent from "./ScorePageContent"; -import { REGIONS_KO } from "@/constants/university"; -import { ApplicationListResponse } from "@/types/application"; -import { RegionKo } from "@/types/university"; - -const PREFERENCE_CHOICE: string[] = ["1순위", "2순위", "3순위"]; +export const metadata: Metadata = { + title: "점수 공유 현황", +}; const ScorePage = () => { - const router = useRouter(); - const [loading, setLoading] = useState(true); - // 검색 - const [searchActive, setSearchActive] = useState(false); // 검색 창 활성화 여부 - const searchRef = useRef(null); - // 점수 데이터 - const [scoreData, setScoreData] = useState({ - firstChoice: [], - secondChoice: [], - thirdChoice: [], - }); - const [filteredScoreData, setFilteredScoreData] = useState({ - firstChoice: [], - secondChoice: [], - thirdChoice: [], - }); - const [preference, setPreference] = useState<"1순위" | "2순위" | "3순위">("1순위"); - const [filter, setFilter] = useState(""); - - const [showNeedApply, setShowNeedApply] = useState(false); - - useEffect(() => { - const fetchData = async () => { - try { - if (true) { - const scoreResponse = await getCompetitorsApplicationListApi(); - - const scoreResponseData = scoreResponse.data; - scoreResponseData.firstChoice.sort((a, b) => b.applicants.length - a.applicants.length); - scoreResponseData.secondChoice.sort((a, b) => b.applicants.length - a.applicants.length); - scoreResponseData.thirdChoice.sort((a, b) => b.applicants.length - a.applicants.length); - setScoreData(scoreResponseData); - setFilteredScoreData(scoreResponseData); - } - } catch (err) { - if (err.response) { - if (err.response.status === 404) { - setShowNeedApply(true); - } else if (err.response.status === 401 || err.response.status === 403) { - alert("로그인이 필요합니다"); - document.location.href = "/login"; - } else { - alert(err.response.data?.message); - } - } else { - console.error("Error", err.message); - } - } finally { - setLoading(false); - } - }; - fetchData(); - }, []); - - const handleSearch = (event: React.FormEvent) => { - event.preventDefault(); - const keyWord = searchRef.current?.value || ""; - setFilter(""); - setFilteredScoreData( - keyWord - ? { - firstChoice: scoreData.firstChoice.filter((sheet) => sheet.koreanName.includes(keyWord)), - secondChoice: scoreData.secondChoice.filter((sheet) => sheet.koreanName.includes(keyWord)), - thirdChoice: scoreData.thirdChoice.filter((sheet) => sheet.koreanName.includes(keyWord)), - } - : scoreData, - ); - setSearchActive(false); - }; - - const handleSearchField = (keyWord: string) => { - if (searchRef.current) { - searchRef.current.value = keyWord; - } - }; - - const handleSearchClick = () => { - setSearchActive(true); - }; - - const hotKeyWords = ["RMIT", "오스트라바", "칼스루에", "그라츠", "추오", "프라하", "보라스", "빈", "메모리얼"]; - - useEffect(() => { - if (filter) { - setFilteredScoreData({ - firstChoice: scoreData.firstChoice.filter((sheet) => sheet.region === filter), - secondChoice: scoreData.secondChoice.filter((sheet) => sheet.region === filter), - thirdChoice: scoreData.thirdChoice.filter((sheet) => sheet.region === filter), - }); - } else { - setFilteredScoreData(scoreData); - } - }, [filter, scoreData]); - - if (loading) { - return ; - } - - const getScoreSheet = () => { - if (preference === "1순위") { - return filteredScoreData.firstChoice; - } - if (preference === "2순위") { - return filteredScoreData.secondChoice; - } - if (preference === "3순위") { - return filteredScoreData.thirdChoice; - } - return []; - }; - - if (searchActive) { - return ( - <> - - {}} /> - { - handleSearchField(e); - }} - /> - - ); - } - return ( <> - - - - - { - router.push("/"); - }} - handleConfirm={() => { - router.push("/application/apply"); - }} - title="" - content={"점수 공유현황을 확인하려면 지원절차를\n진행해주세요."} - cancelText="확인" - approveText="학교 지원하기" - /> + ); }; diff --git a/src/app/community/[boardCode]/CommunityPageContent.tsx b/src/app/community/[boardCode]/CommunityPageContent.tsx new file mode 100644 index 00000000..6b0b7447 --- /dev/null +++ b/src/app/community/[boardCode]/CommunityPageContent.tsx @@ -0,0 +1,83 @@ +"use client"; + +import { useRouter } from "next/navigation"; +import { useEffect, useState } from "react"; + +import { getPostListApi } from "@/services/community"; + +import CloudSpinnerPage from "@/components/loading/CloudSpinnerPage"; +import ButtonTab from "@/components/ui/ButtonTab"; + +import CommunityRegionSelector from "./CommunityRegionSelector"; +import PostCards from "./PostCards"; +import PostWriteButton from "./PostWriteButton"; + +import { COMMUNITY_BOARDS, COMMUNITY_CATEGORIES } from "@/constants/commnunity"; +import { ListPost } from "@/types/community"; + +interface CommunityPageContentProps { + boardCode: string; +} + +const CommunityPageContent = ({ boardCode }: CommunityPageContentProps) => { + const router = useRouter(); + const [boardDisplayName, setBoardDisplayName] = useState("자유"); + const [category, setCategory] = useState("전체"); + const [posts, setPosts] = useState([]); + const [isLoading, setIsLoading] = useState(false); + + useEffect(() => { + const fetchPosts = async () => { + setIsLoading(true); + try { + const res = await getPostListApi(boardCode, category); + setPosts(res.data.reverse()); + } catch (err) { + if (err.response) { + console.error("Axios response error", err.response); + if (err.response.status === 401 || err.response.status === 403) { + alert("로그인이 필요합니다"); + document.location.href = "/login"; + } else { + alert(err.response.data?.message); + } + } else { + console.error("Error", err.message); + alert(err.message); + } + } finally { + setIsLoading(false); + } + }; + fetchPosts(); + setBoardDisplayName(COMMUNITY_BOARDS.find((b) => b.code === boardCode)?.nameKo || "자유"); + }, [boardCode, category]); + + const handleBoardChange = (newBoard: string) => { + router.push(`/community/${newBoard}`); + }; + + const postWriteHandler = () => { + router.push(`/community/${boardCode}/create`); + }; + + return ( +
+ + + {isLoading ? : } + +
+ ); +}; + +export default CommunityPageContent; diff --git a/src/app/community/[boardCode]/[postId]/PostPageContent.tsx b/src/app/community/[boardCode]/[postId]/PostPageContent.tsx new file mode 100644 index 00000000..4fbaf8c3 --- /dev/null +++ b/src/app/community/[boardCode]/[postId]/PostPageContent.tsx @@ -0,0 +1,88 @@ +"use client"; + +import { useRouter } from "next/navigation"; +import { useEffect, useState } from "react"; + +import { getPostDetailApi } from "@/services/community"; + +import TopDetailNavigation from "@/components/layout/TopDetailNavigation"; +import CloudSpinnerPage from "@/components/loading/CloudSpinnerPage"; + +import CommentWrite from "./CommentWrite"; +import Comments from "./Comments"; +import KebabMenu from "./KebabMenu"; +import Post from "./Post"; + +import { Post as PostType } from "@/types/community"; + +interface PostPageContentProps { + boardCode: string; + postId: number; +} + +const PostPageContent = ({ boardCode, postId }: PostPageContentProps) => { + const router = useRouter(); + const [post, setPost] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [curSelectedComment, setCurSelectedComment] = useState(null); + + const fetchPosts = async () => { + await getPostDetailApi(postId) + .then((res) => { + setPost(res.data); + }) + .catch((err) => { + if (err.response) { + console.error("Axios response error", err.response); + if (err.response.status === 401 || err.response.status === 403) { + alert("로그인이 필요합니다"); + document.location.href = "/login"; + } else { + alert(err.response.data?.message); + } + } else { + console.error("Error", err.message); + alert(err.message); + } + }); + setIsLoading(false); + }; + + useEffect(() => { + fetchPosts(); + }, [postId]); + + if (isLoading || post === null) { + return ; + } + + return ( +
+ { + router.push(`/community/${boardCode}`); + }} + icon={} + /> + + { + router.refresh(); + }} + setCurSelectedComment={setCurSelectedComment} + onSuccess={fetchPosts} + /> + +
+ ); +}; + +export default PostPageContent; diff --git a/src/app/community/[boardCode]/[postId]/modify/PostModifyContent.tsx b/src/app/community/[boardCode]/[postId]/modify/PostModifyContent.tsx new file mode 100644 index 00000000..8824141a --- /dev/null +++ b/src/app/community/[boardCode]/[postId]/modify/PostModifyContent.tsx @@ -0,0 +1,74 @@ +"use client"; + +import { useRouter } from "next/navigation"; +import { useEffect, useState } from "react"; + +import { getPostDetailApi } from "@/services/community"; + +import CloudSpinnerPage from "@/components/loading/CloudSpinnerPage"; + +import PostModifyForm from "./PostModifyForm"; + +import { Post } from "@/types/community"; + +interface PostModifyContentProps { + boardCode: string; + postId: number; +} + +const PostModifyContent = ({ boardCode, postId }: PostModifyContentProps) => { + const router = useRouter(); + const [post, setPost] = useState(null); + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + const fetchPost = async () => { + try { + const res = await getPostDetailApi(postId); + setPost(res.data); + } catch (err) { + // 에러 처리 + if (err.response) { + console.error("Axios response error", err.response); + if (err.response.status === 401 || err.response.status === 403) { + alert("로그인이 필요합니다"); + document.location.href = "/login"; + } else { + alert(err.response.data?.message); + } + } else { + console.error("Error", err.message); + alert(err.message); + } + // 오류 발생 시 목록 페이지로 이동 + router.push(`/community/${boardCode}`); + } finally { + setIsLoading(false); + } + }; + fetchPost(); + }, [boardCode, postId, router]); + + if (isLoading) { + return ; + } + + if (!post) { + return
게시글을 불러오는 데 오류가 발생했습니다.
; + } + + return ( +
+ +
+ ); +}; + +export default PostModifyContent; diff --git a/src/app/community/[boardCode]/[postId]/modify/page.tsx b/src/app/community/[boardCode]/[postId]/modify/page.tsx index 17108804..1b681f07 100644 --- a/src/app/community/[boardCode]/[postId]/modify/page.tsx +++ b/src/app/community/[boardCode]/[postId]/modify/page.tsx @@ -1,72 +1,28 @@ -"use client"; - import { Metadata } from "next"; -import { useRouter } from "next/navigation"; -import { useEffect, useState } from "react"; -import { getPostDetailApi } from "@/services/community"; +import TopDetailNavigation from "@/components/layout/TopDetailNavigation"; -import PostModifyForm from "./PostModifyForm"; +import PostModifyContent from "./PostModifyContent"; -import { Post } from "@/types/community"; +interface PostModifyPageProps { + params: { + boardCode: string; + postId: string; + }; +} -// export const metadata: Metadata = { -// title: "글 수정", -// }; +export const metadata: Metadata = { + title: "글 수정", +}; -const PostModifyPage = ({ params }: { params: { boardCode: string; postId: string } }) => { +const PostModifyPage = ({ params }: PostModifyPageProps) => { const { boardCode, postId } = params; - const router = useRouter(); - const [post, setPost] = useState(null); - const [isLoading, setIsLoading] = useState(true); - - useEffect(() => { - const fetchPost = async () => { - try { - const res = await getPostDetailApi(Number(postId)); - setPost(res.data); - } catch (err) { - // 에러 처리 - if (err.response) { - console.error("Axios response error", err.response); - if (err.response.status === 401 || err.response.status === 403) { - alert("로그인이 필요합니다"); - document.location.href = "/login"; - } else { - alert(err.response.data?.message); - } - } else { - console.error("Error", err.message); - alert(err.message); - } - // 오류 발생 시 목록 페이지로 이동 - router.push(`/community/${boardCode}`); - } finally { - setIsLoading(false); - } - }; - fetchPost(); - }, [boardCode, postId, router]); - - if (isLoading) { - return
로딩 중...
; // 로딩 스피너 컴포넌트를 사용할 수 있습니다. - } - - if (!post) { - return
게시글을 불러오는 데 오류가 발생했습니다.
; - } return ( -
- -
+ <> + + + ); }; diff --git a/src/app/community/[boardCode]/[postId]/page.tsx b/src/app/community/[boardCode]/[postId]/page.tsx index 7b04828c..f978fa25 100644 --- a/src/app/community/[boardCode]/[postId]/page.tsx +++ b/src/app/community/[boardCode]/[postId]/page.tsx @@ -1,86 +1,25 @@ -"use client"; +import { Metadata } from "next"; -import { useRouter } from "next/navigation"; -import { useEffect, useState } from "react"; +import PostPageContent from "./PostPageContent"; -import { getPostDetailApi } from "@/services/community"; - -import TopDetailNavigation from "@/components/layout/TopDetailNavigation"; -import CloudSpinnerPage from "@/components/loading/CloudSpinnerPage"; - -import CommentWrite from "./CommentWrite"; -import Comments from "./Comments"; -import KebabMenu from "./KebabMenu"; -import Post from "./Post"; +interface PostPageProps { + params: { + boardCode: string; + postId: string; + }; +} -import { Post as PostType } from "@/types/community"; +export const metadata: Metadata = { + title: "게시글", +}; -const PostPage = ({ params }: { params: { boardCode: string; postId: string } }) => { - const router = useRouter(); +const PostPage = ({ params }: PostPageProps) => { const { boardCode } = params; const postId = Number(params.postId); - const [post, setPost] = useState(null); - const [isLoading, setIsLoading] = useState(true); - const [curSelectedComment, setCurSelectedComment] = useState(null); - - const fetchPosts = async () => { - await getPostDetailApi(postId) - .then((res) => { - setPost(res.data); - }) - .catch((err) => { - if (err.response) { - console.error("Axios response error", err.response); - if (err.response.status === 401 || err.response.status === 403) { - alert("로그인이 필요합니다"); - document.location.href = "/login"; - } else { - alert(err.response.data?.message); - } - } else { - console.error("Error", err.message); - alert(err.message); - } - }); - setIsLoading(false); - }; - - useEffect(() => { - fetchPosts(); - }, [postId]); - - if (isLoading || post === null) { - return ; - } return ( <> - {/* 페이지 타이틀을 설정하려면 metadata API를 사용할 수 있습니다 */} - { - router.push(`/community/${boardCode}`); - }} - icon={post.isOwner && } - /> -
- - { - router.refresh(); - }} - setCurSelectedComment={setCurSelectedComment} - onSuccess={fetchPosts} - /> - -
+ ); }; diff --git a/src/app/community/[boardCode]/page.tsx b/src/app/community/[boardCode]/page.tsx index 9d826c53..2b47c465 100644 --- a/src/app/community/[boardCode]/page.tsx +++ b/src/app/community/[boardCode]/page.tsx @@ -1,86 +1,26 @@ -"use client"; - -import { useRouter } from "next/navigation"; -import { useEffect, useState } from "react"; - -import { getPostListApi } from "@/services/community"; +import { Metadata } from "next"; import TopDetailNavigation from "@/components/layout/TopDetailNavigation"; -import CloudSpinnerPage from "@/components/loading/CloudSpinnerPage"; -import ButtonTab from "@/components/ui/ButtonTab"; - -import CommunityRegionSelector from "./CommunityRegionSelector"; -import PostCards from "./PostCards"; -import PostWriteButton from "./PostWriteButton"; -import { COMMUNITY_BOARDS, COMMUNITY_CATEGORIES } from "@/constants/commnunity"; -import { ListPost } from "@/types/community"; +import CommunityPageContent from "./CommunityPageContent"; -// export const metadata: Metadata = { -// title: "커뮤니티", -// }; - -const CommunityPage = ({ params }: { params: { boardCode: string } }) => { - const { boardCode } = params; - const router = useRouter(); - const [boardDisplayName, setBoardDisplayName] = useState("자유"); - const [category, setCategory] = useState("전체"); - const [posts, setPosts] = useState([]); - const [isLoading, setIsLoading] = useState(false); - - useEffect(() => { - const fetchPosts = async () => { - setIsLoading(true); - try { - const res = await getPostListApi(boardCode, category); - setPosts(res.data.reverse()); - } catch (err) { - if (err.response) { - console.error("Axios response error", err.response); - if (err.response.status === 401 || err.response.status === 403) { - alert("로그인이 필요합니다"); - document.location.href = "/login"; - } else { - alert(err.response.data?.message); - } - } else { - console.error("Error", err.message); - alert(err.message); - } - } finally { - setIsLoading(false); - } - }; - fetchPosts(); - setBoardDisplayName(COMMUNITY_BOARDS.find((b) => b.code === boardCode)?.nameKo || "자유"); - }, [boardCode, category]); +export const metadata: Metadata = { + title: "커뮤니티", +}; - const handleBoardChange = (newBoard: string) => { - router.push(`/community/${newBoard}`); +interface CommunityPageProps { + params: { + boardCode: string; }; +} - const postWriteHandler = () => { - router.push(`/community/${boardCode}/create`); - }; +const CommunityPage = ({ params }: CommunityPageProps) => { + const { boardCode } = params; return ( <> -
- - - {isLoading ? : } - -
+ ); }; diff --git a/src/app/login/LoginContent.tsx b/src/app/login/LoginContent.tsx new file mode 100644 index 00000000..b1f4a0eb --- /dev/null +++ b/src/app/login/LoginContent.tsx @@ -0,0 +1,156 @@ +"use client"; + +import Link from "next/link"; +import { useRouter } from "next/navigation"; +import { useEffect, useState } from "react"; + +import { emailAuthApi } from "@/services/auth"; +import { saveAccessToken, saveRefreshToken } from "@/utils/localStorage"; + +import BlockBtn from "@/components/button/BlockBtn"; + +import AppleLoginButton from "./AppleLoginButton"; +import EmailSignUpButton from "./EmailSignUpButton"; +import KakaoLoginButton from "./KakaoLoginButton"; + +import { appleOAuth2CodeResponse } from "@/types/auth"; + +import { useLayout } from "@/context/LayoutContext"; +import { IconSolidConnectionFullBlackLogo } from "@/public/svgs"; + +const LoginContent = () => { + const router = useRouter(); + const { setHideBottomNavigation } = useLayout(); + + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + + useEffect(() => { + setHideBottomNavigation(true); + return () => setHideBottomNavigation(false); + }, [setHideBottomNavigation]); + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Enter") { + handleEmailLogin(); + } + }; + + const kakaoLogin = () => { + if (window.Kakao && window.Kakao.Auth) { + window.Kakao.Auth.authorize({ + redirectUri: `${process.env.NEXT_PUBLIC_WEB_URL}/login/kakao/callback`, + }); + } else { + alert("Kakao SDK를 불러오는 중입니다. 잠시 후 다시 시도해주세요."); + } + }; + + const appleLogin = async () => { + if (!window.AppleID || !window.AppleID.auth) { + alert("Apple SDK를 불러오는 중입니다. 잠시 후 다시 시도해주세요."); + return; + } + + window.AppleID.auth.init({ + clientId: process.env.NEXT_PUBLIC_APPLE_CLIENT_ID, + scope: process.env.NEXT_PUBLIC_APPLE_SCOPE, + redirectURI: `${process.env.NEXT_PUBLIC_WEB_URL}/login/apple/callback`, + usePopup: true, + }); + + try { + const res: appleOAuth2CodeResponse = await window.AppleID.auth.signIn(); + if (res.authorization) { + router.push(`/login/apple/callback?code=${res.authorization.code}`); + } + } catch (error) { + console.log(error); + } + }; + + const handleEmailLogin = async () => { + if (!email.trim()) { + alert("이메일을 입력해주세요."); + return; + } + if (!password) { + alert("비밀번호를 입력해주세요."); + return; + } + try { + const response = await emailAuthApi(email, password); + saveAccessToken(response.data.accessToken); + saveRefreshToken(response.data.refreshToken); + router.push("/"); + } catch (error: any) { + console.error(error); + alert(error.response?.data?.message || "로그인에 실패했습니다."); + } + }; + + return ( +
+
+ + + +
+
+
로그인
+
+ 교환학생을 위한 여정 +
+ 지금 솔리드 커넥션에서 시작하세요. +
+
+ +
+
+
+ setEmail(e.target.value)} + onKeyDown={handleKeyDown} + /> +
+ +
+ setPassword(e.target.value)} + onKeyDown={handleKeyDown} + /> +
+ +
+ 로그인 +
+ +
or
+
+ +
+
+ router.push("/sign-up/email")} /> +
+
+ +
+
+
+
+ ); +}; + +export default LoginContent; diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index d0929ec6..3c9e2b5f 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -1,161 +1,13 @@ -"use client"; - import { Metadata } from "next"; -import Link from "next/link"; -import { useRouter } from "next/navigation"; -import { useEffect, useState } from "react"; - -import { emailAuthApi } from "@/services/auth"; -import { saveAccessToken, saveRefreshToken } from "@/utils/localStorage"; - -import BlockBtn from "@/components/button/BlockBtn"; - -import AppleLoginButton from "./AppleLoginButton"; -import EmailSignUpButton from "./EmailSignUpButton"; -import KakaoLoginButton from "./KakaoLoginButton"; - -import { appleOAuth2CodeResponse } from "@/types/auth"; - -import { useLayout } from "@/context/LayoutContext"; -import { IconSolidConnectionFullBlackLogo } from "@/public/svgs"; - -// export const metadata: Metadata = { -// title: "로그인", -// }; - -const KakaoLoginPage = () => { - const router = useRouter(); - const { setHideBottomNavigation } = useLayout(); - - const [email, setEmail] = useState(""); - const [password, setPassword] = useState(""); - - useEffect(() => { - setHideBottomNavigation(true); - return () => setHideBottomNavigation(false); // 컴포넌트가 언마운트될 때 다시 보이게 설정 - }, [setHideBottomNavigation]); - const handleKeyDown = (e: React.KeyboardEvent) => { - if (e.key === "Enter") { - handleEmailLogin(); - } - }; +import LoginContent from "./LoginContent"; - const kakaoLogin = () => { - if (window.Kakao && window.Kakao.Auth) { - window.Kakao.Auth.authorize({ - redirectUri: `${process.env.NEXT_PUBLIC_WEB_URL}/login/kakao/callback`, - }); - } else { - alert("Kakao SDK를 불러오는 중입니다. 잠시 후 다시 시도해주세요."); - } - }; - - const appleLogin = async () => { - if (!window.AppleID || !window.AppleID.auth) { - alert("Apple SDK를 불러오는 중입니다. 잠시 후 다시 시도해주세요."); - return; - } - - window.AppleID.auth.init({ - clientId: process.env.NEXT_PUBLIC_APPLE_CLIENT_ID, - scope: process.env.NEXT_PUBLIC_APPLE_SCOPE, - redirectURI: `${process.env.NEXT_PUBLIC_WEB_URL}/login/apple/callback`, - usePopup: true, - }); - - try { - const res: appleOAuth2CodeResponse = await window.AppleID.auth.signIn(); - if (res.authorization) { - router.push(`/login/apple/callback?code=${res.authorization.code}`); - } - } catch (error) { - console.log(error); - } - }; - - const handleEmailLogin = async () => { - if (!email.trim()) { - alert("이메일을 입력해주세요."); - return; - } - if (!password) { - alert("비밀번호를 입력해주세요."); - return; - } - try { - const response = await emailAuthApi(email, password); - saveAccessToken(response.data.accessToken); - saveRefreshToken(response.data.refreshToken); - router.push("/"); - } catch (error: any) { - console.error(error); - alert(error.response?.data?.message || "로그인에 실패했습니다."); - } - }; - - return ( -
-
- - - -
-
-
로그인
-
- 교환학생을 위한 여정 -
- 지금 솔리드 커넥션에서 시작하세요. -
-
- -
-
-
- setEmail(e.target.value)} - onKeyDown={handleKeyDown} - /> -
- -
- setPassword(e.target.value)} - onKeyDown={handleKeyDown} - /> -
- -
- 로그인 -
+export const metadata: Metadata = { + title: "로그인", +}; -
or
-
- -
-
- router.push("/sign-up/email")} /> -
-
- -
-
-
-
- ); +const LoginPage = () => { + return ; }; -export default KakaoLoginPage; +export default LoginPage; diff --git a/src/app/my/MyContent.tsx b/src/app/my/MyContent.tsx new file mode 100644 index 00000000..cb1980b3 --- /dev/null +++ b/src/app/my/MyContent.tsx @@ -0,0 +1,201 @@ +"use client"; + +import Link from "next/link"; +import { useRouter } from "next/navigation"; +import { useEffect, useState } from "react"; + +import { deleteAccountApi, signOutApi } from "@/services/auth"; +import { getMyInfoApi } from "@/services/myInfo"; +import { authProviderName } from "@/utils/authUtils"; + +import ConfirmCancelModal from "@/components/modal/ConfirmCancelModal"; + +import { MyInfo } from "@/types/myInfo"; + +import MyInfoCard from "@/app/my/MyInfoCard"; +import MyMenu from "@/app/my/MyMenu"; +import MyMenuGroup from "@/app/my/MyMenuGroup"; +import { IconMyMenuCalendar, IconMyMenuLock, IconMyMenuPerson } from "@/public/svgs/my"; + +const roleDisplay = { + MENTO: "Mento", + MENTEE: "Mentee", +}; + +const MyContent = () => { + const router = useRouter(); + const [myInfo, setMyInfo] = useState(null); + const [showLogout, setShowLogout] = useState(false); + const [showWithdraw, setShowWithdraw] = useState(false); + + useEffect(() => { + const fetchMyData = async () => { + await getMyInfoApi() + .then((res) => { + setMyInfo(res.data); + }) + .catch((err) => { + if (err.response) { + console.error("Axios response error", err.response); + if (err.response.status === 401 || err.response.status === 403) { + // alert("로그인이 필요합니다"); + document.location.href = "/login"; + } else { + alert(err.response.data?.message); + } + } else { + console.error("Error", err.message); + alert(err.message); + } + }); + }; + fetchMyData(); + }, []); + + const handleLogout = async () => { + await signOutApi() + .then(() => {}) + .catch((err) => { + if (err.response) { + console.error("Axios response error", err.response); + if (err.response.status === 401 || err.response.status === 403) { + document.location.href = "/login"; + } else { + alert(err.response.data?.message); + } + } else { + console.error("Error", err.message); + alert(err.message); + } + }) + .finally(() => { + localStorage.removeItem("accessToken"); + localStorage.removeItem("refreshToken"); + router.push("/"); + }); + }; + + const handleWithdraw = async () => { + await deleteAccountApi() + .then(() => { + localStorage.removeItem("accessToken"); + localStorage.removeItem("refreshToken"); + window.confirm("탈퇴 신청이 완료되었습니다. 30일 후 계정이 삭제됩니다."); + router.push("/"); + }) + .catch((err) => { + if (err.response) { + console.error("Axios response error", err.response); + if (err.response.status === 401 || err.response.status === 403) { + document.location.href = "/login"; + } else { + alert(err.response.data?.message); + } + } else { + console.error("Error", err.message); + alert(err.message); + } + }); + }; + + const toggleLogout = () => { + setShowLogout(!showLogout); + }; + + const toggleWithdraw = () => { + setShowWithdraw(!showWithdraw); + }; + + if (!myInfo) { + return null; + } + + return ( + <> +
+
+
+ 프로필 +
+
+
+ {myInfo.nickname || "닉네임"} +
+ + {myInfo.role in roleDisplay ? roleDisplay[myInfo.role] : "Mentee"} + +
+
+ +
INHA Univ
+
+
+ +
+ +
+
+ } subject="내 정보"> + + + + + + + + + + + } subject="내 활동"> + + + + + + + + } subject="내 계정"> +
+ 솔커 계정 +
+ {authProviderName(myInfo.authType)} 로그인 + {myInfo.email} +
+
+
+ +
+
+ +
+
+
+ + + +
+ + ); +}; + +export default MyContent; diff --git a/src/app/my/favorite/FavoriteContent.tsx b/src/app/my/favorite/FavoriteContent.tsx new file mode 100644 index 00000000..5b427985 --- /dev/null +++ b/src/app/my/favorite/FavoriteContent.tsx @@ -0,0 +1,65 @@ +"use client"; + +import { useEffect, useState } from "react"; + +import { getMyWishUniversityApi } from "@/services/myInfo"; + +import UniversityCards from "@/components/college/UniversityCards"; +import ScrollTab from "@/components/ui/ScrollTab"; + +import { ListUniversity } from "@/types/university"; + +const FavoriteContent = () => { + const [wishColleges, setWishColleges] = useState(null); + + useEffect(() => { + const fetchWishColleges = async () => { + await getMyWishUniversityApi() + .then((res) => { + setWishColleges(res.data); + }) + .catch((err) => { + if (err.response) { + console.error("Axios response error", err.response); + if (err.response.status === 401 || err.response.status === 403) { + alert("로그인이 필요합니다"); + document.location.href = "/login"; + } else { + alert(err.response.data?.message); + } + } else { + console.error("Error", err.message); + alert(err.message); + } + }); + }; + fetchWishColleges(); + }, []); + + const tabs = ["위시학교"]; + const [tab, setTab] = useState(tabs[0]); + + if (!wishColleges) { + return null; + } + + return ( + <> + + {(() => { + switch (tab) { + case tabs[0]: + return ( +
+ +
+ ); + default: + return null; + } + })()} + + ); +}; + +export default FavoriteContent; diff --git a/src/app/my/favorite/page.tsx b/src/app/my/favorite/page.tsx index 84ccf90d..8108c2bb 100644 --- a/src/app/my/favorite/page.tsx +++ b/src/app/my/favorite/page.tsx @@ -1,76 +1,20 @@ -"use client"; +import { Metadata } from "next"; -import Head from "next/head"; -import { useEffect, useState } from "react"; - -import { getMyWishUniversityApi } from "@/services/myInfo"; - -import UniversityCards from "@/components/college/UniversityCards"; import TopDetailNavigation from "@/components/layout/TopDetailNavigation"; -import ScrollTab from "@/components/ui/ScrollTab"; - -import { ListUniversity } from "@/types/university"; -const MyScrapPage = () => { - const [wishColleges, setWishColleges] = useState(null); +import FavoriteContent from "./FavoriteContent"; - useEffect(() => { - const fetchWishColleges = async () => { - await getMyWishUniversityApi() - .then((res) => { - setWishColleges(res.data); - }) - .catch((err) => { - if (err.response) { - console.error("Axios response error", err.response); - if (err.response.status === 401 || err.response.status === 403) { - alert("로그인이 필요합니다"); - document.location.href = "/login"; - } else { - alert(err.response.data?.message); - } - } else { - console.error("Error", err.message); - alert(err.message); - } - }); - }; - fetchWishColleges(); - }, []); - - // const tabs = ["스크랩 한 글", "멘토", "위시학교"]; - const tabs = ["위시학교"]; - const [tab, setTab] = useState(tabs[0]); - - if (!wishColleges) { - return null; - } +export const metadata: Metadata = { + title: "즐겨찾기", +}; +const FavoritePage = () => { return ( <> - - 즐거찾기 - - - - {(() => { - switch (tab) { - case tabs[0]: - return ( -
- -
- ); - // case tabs[1]: - // return ; - // case tabs[2]: - // return <>; - default: - return null; - } - })()} + + ); }; -export default MyScrapPage; +export default FavoritePage; diff --git a/src/app/my/modify/ModifyContent.tsx b/src/app/my/modify/ModifyContent.tsx new file mode 100644 index 00000000..70b4e904 --- /dev/null +++ b/src/app/my/modify/ModifyContent.tsx @@ -0,0 +1,60 @@ +"use client"; + +import { useEffect, useState } from "react"; + +import { getMyInfoApi } from "@/services/myInfo"; + +import { MyInfo } from "@/types/myInfo"; + +import MyInfoModifyForm from "@/app/my/modify/MyInfoModifyForm"; +import MyProfileImageModify from "@/app/my/modify/MyProfileImageModify"; + +const roleDisplay = { + MENTO: "멘토", + MENTEE: "멘티", +}; + +const ModifyContent = () => { + const [myInfo, setMyInfo] = useState(null); + + useEffect(() => { + const fetchMyData = async () => { + try { + const res = await getMyInfoApi(); + setMyInfo(res.data); + } catch (err) { + if (err.response) { + console.error("Axios response error", err.response); + if (err.response.status === 401 || err.response.status === 403) { + alert("로그인이 필요합니다"); + document.location.href = "/login"; + } else { + alert(err.response.data?.message); + } + } else { + console.error("Error", err.message); + alert(err.message); + } + } + }; + fetchMyData(); + }, []); + + if (!myInfo) { + return null; + } + + return ( +
+
+
+ {myInfo.role ? roleDisplay[myInfo.role] : "멘티"} +
+ +
+ +
+ ); +}; + +export default ModifyContent; diff --git a/src/app/my/modify/page.tsx b/src/app/my/modify/page.tsx index 9729f77e..69268615 100644 --- a/src/app/my/modify/page.tsx +++ b/src/app/my/modify/page.tsx @@ -1,69 +1,20 @@ -"use client"; - -import { useEffect, useState } from "react"; - -import { getMyInfoApi } from "@/services/myInfo"; +import { Metadata } from "next"; import TopDetailNavigation from "@/components/layout/TopDetailNavigation"; -import { MyInfo } from "@/types/myInfo"; +import ModifyContent from "./ModifyContent"; -import MyInfoModifyForm from "@/app/my/modify/MyInfoModifyForm"; -import MyProfileImageModify from "@/app/my/modify/MyProfileImageModify"; - -const roleDisplay = { - MENTO: "멘토", - MENTEE: "멘티", +export const metadata: Metadata = { + title: "프로필 수정", }; -// export const metadata = { -// title: "프로필 수정", -// }; - -const MyModifyPage = () => { - const [myInfo, setMyInfo] = useState(null); - - useEffect(() => { - const fetchMyData = async () => { - try { - const res = await getMyInfoApi(); - setMyInfo(res.data); - } catch (err) { - if (err.response) { - console.error("Axios response error", err.response); - if (err.response.status === 401 || err.response.status === 403) { - alert("로그인이 필요합니다"); - document.location.href = "/login"; - } else { - alert(err.response.data?.message); - } - } else { - console.error("Error", err.message); - alert(err.message); - } - } - }; - fetchMyData(); - }, []); - - if (!myInfo) { - return null; - } - +const ModifyPage = () => { return ( <> -
-
-
- {myInfo.role ? roleDisplay[myInfo.role] : "멘티"} -
- -
- -
+ ); }; -export default MyModifyPage; +export default ModifyPage; diff --git a/src/app/my/page.tsx b/src/app/my/page.tsx index 86145d47..81f7dc50 100644 --- a/src/app/my/page.tsx +++ b/src/app/my/page.tsx @@ -1,205 +1,18 @@ -"use client"; - -import Head from "next/head"; -import Link from "next/link"; -import { useRouter } from "next/navigation"; -import { useEffect, useState } from "react"; - -import { deleteAccountApi, signOutApi } from "@/services/auth"; -import { getMyInfoApi } from "@/services/myInfo"; -import { authProviderName } from "@/utils/authUtils"; +import { Metadata } from "next"; import TopDetailNavigation from "@/components/layout/TopDetailNavigation"; -import ConfirmCancelModal from "@/components/modal/ConfirmCancelModal"; -import { MyInfo } from "@/types/myInfo"; +import MyContent from "./MyContent"; -import MyInfoCard from "@/app/my/MyInfoCard"; -import MyMenu from "@/app/my/MyMenu"; -import MyMenuGroup from "@/app/my/MyMenuGroup"; -import { IconMyMenuCalendar, IconMyMenuLock, IconMyMenuPerson } from "@/public/svgs/my"; - -const roleDisplay = { - MENTO: "Mento", - MENTEE: "Mentee", +export const metadata: Metadata = { + title: "마이페이지", }; const MyPage = () => { - const router = useRouter(); - const [myInfo, setMyInfo] = useState(null); - const [showLogout, setShowLogout] = useState(false); - const [showWithdraw, setShowWithdraw] = useState(false); - - useEffect(() => { - const fetchMyData = async () => { - await getMyInfoApi() - .then((res) => { - setMyInfo(res.data); - }) - .catch((err) => { - if (err.response) { - console.error("Axios response error", err.response); - if (err.response.status === 401 || err.response.status === 403) { - alert("로그인이 필요합니다"); - document.location.href = "/login"; - } else { - alert(err.response.data?.message); - } - } else { - console.error("Error", err.message); - alert(err.message); - } - }); - }; - fetchMyData(); - }, []); - - const handleLogout = async () => { - await signOutApi() - .then(() => {}) - .catch((err) => { - if (err.response) { - console.error("Axios response error", err.response); - if (err.response.status === 401 || err.response.status === 403) { - document.location.href = "/login"; - } else { - alert(err.response.data?.message); - } - } else { - console.error("Error", err.message); - alert(err.message); - } - }) - .finally(() => { - localStorage.removeItem("accessToken"); - localStorage.removeItem("refreshToken"); - router.push("/"); // API 호출과 토큰 제거 작업이 모두 완료된 후에 페이지 이동 - }); - }; - - const handleWithdraw = async () => { - await deleteAccountApi() - .then(() => { - localStorage.removeItem("accessToken"); - localStorage.removeItem("refreshToken"); - window.confirm("탈퇴 신청이 완료되었습니다. 30일 후 계정이 삭제됩니다."); - router.push("/"); - }) - .catch((err) => { - if (err.response) { - console.error("Axios response error", err.response); - if (err.response.status === 401 || err.response.status === 403) { - document.location.href = "/login"; - } else { - alert(err.response.data?.message); - } - } else { - console.error("Error", err.message); - alert(err.message); - } - }); - }; - - const toggleLogout = () => { - setShowLogout(!showLogout); - }; - - const toggleWithdraw = () => { - setShowWithdraw(!showWithdraw); - }; - - if (!myInfo) { - return null; - } - return ( <> - - 마이페이지 - -
-
-
- 프로필 -
-
-
- {myInfo.nickname || "닉네임"} -
- - {myInfo.role in roleDisplay ? roleDisplay[myInfo.role] : "Mentee"} - -
-
- -
INHA Univ
-
-
- -
- -
-
- } subject="내 정보"> - - - - - - - - - - - } subject="내 활동"> - - - - - - - - } subject="내 계정"> -
- 솔커 계정 -
- {authProviderName(myInfo.authType)} 로그인 - {myInfo.email} -
-
-
- -
-
- -
-
-
- - - -
+ ); };