From 91b55b2d0aae6d319f22784b5b16772b2f490480 Mon Sep 17 00:00:00 2001 From: hyeonjiroh Date: Mon, 7 Jul 2025 23:33:33 +0900 Subject: [PATCH 1/7] =?UTF-8?q?feat:=20env=20=ED=8C=8C=EC=9D=BC=EC=97=90?= =?UTF-8?q?=20base=20url=20=EC=A0=80=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/lib/fetcher.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/app/lib/fetcher.ts diff --git a/src/app/lib/fetcher.ts b/src/app/lib/fetcher.ts new file mode 100644 index 0000000..e69de29 From a681bd5f0b8431b3b417928f046fd91ddbc044e6 Mon Sep 17 00:00:00 2001 From: hyeonjiroh Date: Mon, 7 Jul 2025 23:44:36 +0900 Subject: [PATCH 2/7] =?UTF-8?q?chore:=20=EB=A1=9C=EC=BB=AC=20=EC=8A=A4?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=EC=A7=80=20=EC=9C=A0=EC=A0=80=20=EC=95=84?= =?UTF-8?q?=EC=9D=B4=EB=94=94=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/map/PopupTestPage/PopupTestPage.jsx | 4 ++-- src/app/recommend/page.tsx | 4 ++-- src/utils/createNewUser.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/map/PopupTestPage/PopupTestPage.jsx b/src/app/map/PopupTestPage/PopupTestPage.jsx index 1b4e350..8bfbd82 100644 --- a/src/app/map/PopupTestPage/PopupTestPage.jsx +++ b/src/app/map/PopupTestPage/PopupTestPage.jsx @@ -22,10 +22,10 @@ export default function PopupTestPage({ routing }) { }; const handleSubmitClick = async () => { - const USID = localStorage.getItem("USID") || ""; + const userId = localStorage.getItem("userId") || ""; const payload = { - clientId: USID, + clientId: userId, satisfactions: satisfactions, }; diff --git a/src/app/recommend/page.tsx b/src/app/recommend/page.tsx index 194333e..4686b7e 100644 --- a/src/app/recommend/page.tsx +++ b/src/app/recommend/page.tsx @@ -12,13 +12,13 @@ export default function RecommendPage() { useEffect(() => { const submitTodayMood = async () => { - const USID = localStorage.getItem("USID") || ""; + const userId = localStorage.getItem("userId") || ""; const onboarding = JSON.parse( localStorage.getItem("onboardingAnswers") ?? "[]" ); const payload = { - clientId: USID, + clientId: userId, age: Number(onboarding[0]?.substr(0, 2) || 0), gender: onboarding[1], resident: onboarding[2], diff --git a/src/utils/createNewUser.ts b/src/utils/createNewUser.ts index b6cce27..1519702 100644 --- a/src/utils/createNewUser.ts +++ b/src/utils/createNewUser.ts @@ -1,6 +1,6 @@ export function createNewUser() { const time = new Date(); - const userID = + const userId = "" + time.getFullYear() + time.getMonth() + @@ -11,7 +11,7 @@ export function createNewUser() { time.getMilliseconds() + Math.floor(Math.random() * 1000); - localStorage.setItem("USID", userID); + localStorage.setItem("userId", userId); localStorage.setItem("onboardingAnswers", JSON.stringify(Array(7).fill(""))); localStorage.setItem("todayMoodAnswers", JSON.stringify(Array(2).fill(""))); } From d60c3dc6f3fe1fde0f0653f7771ba240e080e838 Mon Sep 17 00:00:00 2001 From: hyeonjiroh Date: Mon, 7 Jul 2025 23:51:37 +0900 Subject: [PATCH 3/7] =?UTF-8?q?chore:=20JS=20=ED=8C=8C=EC=9D=BC=EC=9D=84?= =?UTF-8?q?=20TS=EB=A1=9C=20=EB=B3=80=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constants/{surveyData.js => surveyData.ts} | 0 src/constants/{transitionData.js => transitionData.ts} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/constants/{surveyData.js => surveyData.ts} (100%) rename src/constants/{transitionData.js => transitionData.ts} (100%) diff --git a/src/constants/surveyData.js b/src/constants/surveyData.ts similarity index 100% rename from src/constants/surveyData.js rename to src/constants/surveyData.ts diff --git a/src/constants/transitionData.js b/src/constants/transitionData.ts similarity index 100% rename from src/constants/transitionData.js rename to src/constants/transitionData.ts From d8ad86ac5785e2ad42d94a1e7028053fe26b2c8d Mon Sep 17 00:00:00 2001 From: hyeonjiroh Date: Tue, 8 Jul 2025 00:28:38 +0900 Subject: [PATCH 4/7] =?UTF-8?q?feat:=20API=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EC=A0=95=EC=9D=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/lib/type.ts | 7 ------ .../_components/SidePanel/SpaceCard.tsx | 2 +- .../recommend/_components/SidePanel/index.tsx | 2 +- .../lib/api.ts => lib/apis/recommendation.ts} | 0 .../lib/fetcher.ts => lib/apis/update.ts} | 0 src/lib/axiosInstance.ts | 7 ++++++ src/lib/type.ts | 22 +++++++++++++++++++ 7 files changed, 31 insertions(+), 9 deletions(-) delete mode 100644 src/app/lib/type.ts rename src/{app/lib/api.ts => lib/apis/recommendation.ts} (100%) rename src/{app/lib/fetcher.ts => lib/apis/update.ts} (100%) create mode 100644 src/lib/axiosInstance.ts create mode 100644 src/lib/type.ts diff --git a/src/app/lib/type.ts b/src/app/lib/type.ts deleted file mode 100644 index dcd93f1..0000000 --- a/src/app/lib/type.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface RecommendationResponse { - title: string; - position: string; - category: string; - image: string; - url: string; -} diff --git a/src/app/recommend/_components/SidePanel/SpaceCard.tsx b/src/app/recommend/_components/SidePanel/SpaceCard.tsx index 1a17655..8a43112 100644 --- a/src/app/recommend/_components/SidePanel/SpaceCard.tsx +++ b/src/app/recommend/_components/SidePanel/SpaceCard.tsx @@ -1,6 +1,6 @@ import Image from "next/image"; import Temp from "@/assets/icons/temp.jpg"; -import { RecommendationResponse } from "@/app/lib/type"; +import { RecommendationResponse } from "@/lib/type"; export default function SpaceCard({ spaceData, diff --git a/src/app/recommend/_components/SidePanel/index.tsx b/src/app/recommend/_components/SidePanel/index.tsx index a6454ff..c5b91fb 100644 --- a/src/app/recommend/_components/SidePanel/index.tsx +++ b/src/app/recommend/_components/SidePanel/index.tsx @@ -1,7 +1,7 @@ import SpaceCard from "./SpaceCard"; import Image from "next/image"; import ChevronLeft from "@/assets/icons/chevron-left.png"; -import { RecommendationResponse } from "@/app/lib/type"; +import { RecommendationResponse } from "@/lib/type"; export default function SidePanel({ spaceData, diff --git a/src/app/lib/api.ts b/src/lib/apis/recommendation.ts similarity index 100% rename from src/app/lib/api.ts rename to src/lib/apis/recommendation.ts diff --git a/src/app/lib/fetcher.ts b/src/lib/apis/update.ts similarity index 100% rename from src/app/lib/fetcher.ts rename to src/lib/apis/update.ts diff --git a/src/lib/axiosInstance.ts b/src/lib/axiosInstance.ts new file mode 100644 index 0000000..016975b --- /dev/null +++ b/src/lib/axiosInstance.ts @@ -0,0 +1,7 @@ +import axios from "axios"; + +const axiosInstance = axios.create({ + baseURL: process.env.NEXT_PUBLIC_API_URL, +}); + +export default axiosInstance; diff --git a/src/lib/type.ts b/src/lib/type.ts new file mode 100644 index 0000000..b22e65f --- /dev/null +++ b/src/lib/type.ts @@ -0,0 +1,22 @@ +export interface RecommendationRequest { + clientId: string; + age: number; + gender: "남자" | "여자"; + resident: "새만금" | "군산" | "김제" | "부안"; + city: "새만금" | "군산" | "김제" | "부안"; + want: string; + mood: string; +} + +export interface RecommendationResponse { + title: string; + position: string; + category: "FESTIVAL" | "EVENT" | "TOUR" | "CULTURE"; + image: string; + url: string; +} + +export interface UpdateRequest { + clientId: string; + satisfactions: number[]; +} From 6798e8de6fd68af973679e6ec95689f4dd57f9c3 Mon Sep 17 00:00:00 2001 From: hyeonjiroh Date: Tue, 8 Jul 2025 01:12:28 +0900 Subject: [PATCH 5/7] =?UTF-8?q?feat:=20API=20=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/recommend/page.tsx | 41 ++++++++++++---------------------- src/lib/apis/recommendation.ts | 0 src/lib/apis/survey.ts | 23 +++++++++++++++++++ src/lib/apis/update.ts | 0 4 files changed, 37 insertions(+), 27 deletions(-) delete mode 100644 src/lib/apis/recommendation.ts create mode 100644 src/lib/apis/survey.ts delete mode 100644 src/lib/apis/update.ts diff --git a/src/app/recommend/page.tsx b/src/app/recommend/page.tsx index 4686b7e..19affec 100644 --- a/src/app/recommend/page.tsx +++ b/src/app/recommend/page.tsx @@ -1,7 +1,7 @@ "use client"; import { useEffect, useState } from "react"; -import axios from "axios"; +import { fetchRecommendation } from "@/lib/apis/survey"; import SideBar from "./_components/SideBar"; import SidePanel from "./_components/SidePanel"; import BackToSurveyButton from "./_components/BackToSurveyButton"; @@ -11,35 +11,22 @@ export default function RecommendPage() { const [spaceData, setSpaceData] = useState([]); useEffect(() => { - const submitTodayMood = async () => { - const userId = localStorage.getItem("userId") || ""; - const onboarding = JSON.parse( - localStorage.getItem("onboardingAnswers") ?? "[]" - ); + const userId = localStorage.getItem("userId") || ""; + const onboarding = JSON.parse( + localStorage.getItem("onboardingAnswers") ?? "[]" + ); - const payload = { - clientId: userId, - age: Number(onboarding[0]?.substr(0, 2) || 0), - gender: onboarding[1], - resident: onboarding[2], - city: onboarding[3], - want: onboarding[5], - mood: onboarding[6], - }; - - try { - const res = await axios.post( - "https://saegil.store/api/survey/recommendation", - payload - ); - setSpaceData(res.data); - } catch (err) { - console.error("추천 API 실패:", err); - alert("추천 정보를 불러오는 데 실패했어요."); - } + const payload = { + clientId: userId, + age: Number(onboarding[0]?.substr(0, 2) || 0), + gender: onboarding[1], + resident: onboarding[2], + city: onboarding[3], + want: onboarding[5], + mood: onboarding[6], }; - submitTodayMood(); + fetchRecommendation(payload).then(setSpaceData); }, []); return ( diff --git a/src/lib/apis/recommendation.ts b/src/lib/apis/recommendation.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/lib/apis/survey.ts b/src/lib/apis/survey.ts new file mode 100644 index 0000000..c6bfb98 --- /dev/null +++ b/src/lib/apis/survey.ts @@ -0,0 +1,23 @@ +import axios from "@/lib/axiosInstance"; +import { RecommendationRequest, UpdateRequest } from "../type"; + +// 사용자 설문 결과 요청 +export async function fetchRecommendation(payload: RecommendationRequest) { + try { + const res = await axios.post("/survey/recommendation", payload); + return res.data; + } catch (err) { + console.error("추천 API 실패:", err); + alert("추천 정보를 불러오는 데 실패했어요."); + } +} + +// 사용자 설문 결과 만족도 반영 요청 +export async function updateSatisfactionScore(payload: UpdateRequest) { + try { + await axios.post("/survey/update", payload); + } catch (err) { + console.error("만족도 API 호출 실패:", err); + alert("만족도 정보를 제출하는 데 실패했어요."); + } +} diff --git a/src/lib/apis/update.ts b/src/lib/apis/update.ts deleted file mode 100644 index e69de29..0000000 From bd8dae7b91625c3874c3808674afae275b836a2e Mon Sep 17 00:00:00 2001 From: hyeonjiroh Date: Tue, 8 Jul 2025 01:46:39 +0900 Subject: [PATCH 6/7] =?UTF-8?q?feat:=20=EC=B6=94=EC=B2=9C=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EB=B6=88=EB=9F=AC?= =?UTF-8?q?=EC=98=A4=EB=8A=94=20=EB=8F=99=EC=95=88=20=EB=A1=9C=EB=94=A9=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=ED=91=9C=EC=8B=9C=EB=90=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SurveyScreen/hooks/useSurvey.ts | 13 +++++++---- src/app/_components/SurveyScreen/index.tsx | 2 +- .../_components/TransitionScreen/index.tsx | 14 ++++------- src/app/page.tsx | 5 +--- src/app/recommend/page.tsx | 23 ++++++++++++++++++- src/lib/apis/survey.ts | 4 ++-- 6 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/app/_components/SurveyScreen/hooks/useSurvey.ts b/src/app/_components/SurveyScreen/hooks/useSurvey.ts index 86a0929..dd03636 100644 --- a/src/app/_components/SurveyScreen/hooks/useSurvey.ts +++ b/src/app/_components/SurveyScreen/hooks/useSurvey.ts @@ -1,12 +1,15 @@ import { useState } from "react"; +import { useRouter } from "next/navigation"; import { surveyData } from "@/constants/surveyData"; interface UseSurveyProps { type: "onboarding" | "todayMood"; - routing: (page: string) => void; + routing?: (page: string) => void; } export default function useSurvey({ type, routing }: UseSurveyProps) { + const router = useRouter(); + const questions = surveyData[type]; const storageKey = `${type}Answers`; @@ -35,9 +38,11 @@ export default function useSurvey({ type, routing }: UseSurveyProps) { const handleNextClick = () => { if (currentQuestion === questions.length - 1) { - routing( - type === "onboarding" ? "ToMoodTransition" : "ToRecommendTransition" - ); + if (routing) { + routing("ToMoodTransition"); + } else { + router.push("/recommend"); + } } else { setCurrentQuestion((prev) => prev + 1); } diff --git a/src/app/_components/SurveyScreen/index.tsx b/src/app/_components/SurveyScreen/index.tsx index 3a32dc8..cc8599e 100644 --- a/src/app/_components/SurveyScreen/index.tsx +++ b/src/app/_components/SurveyScreen/index.tsx @@ -7,7 +7,7 @@ import Button from "@/components/Button"; interface SurveyScreenProps { type: "onboarding" | "todayMood"; - routing: (page: string) => void; + routing?: (page: string) => void; } export default function SurveyScreen({ type, routing }: SurveyScreenProps) { diff --git a/src/app/_components/TransitionScreen/index.tsx b/src/app/_components/TransitionScreen/index.tsx index 1e13781..44fc895 100644 --- a/src/app/_components/TransitionScreen/index.tsx +++ b/src/app/_components/TransitionScreen/index.tsx @@ -1,7 +1,6 @@ "use client"; import { useEffect } from "react"; -import { useRouter } from "next/navigation"; import { transitionData } from "@/constants/transitionData"; import Image from "next/image"; @@ -14,18 +13,15 @@ export default function TransitionScreen({ type, routing, }: TransitionScreenProps) { - const router = useRouter(); const transitionContent = transitionData[type]; useEffect(() => { - setTimeout(() => { - if (routing) { + if (routing) { + setTimeout(() => { routing("TodayMoodSurvey"); - } else { - router.push("/recommend"); - } - }, 1000); - }, [transitionContent, routing, router]); + }, 1000); + } + }, [transitionContent, routing]); return (
diff --git a/src/app/page.tsx b/src/app/page.tsx index bdb274e..ff44937 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -18,13 +18,10 @@ export default function Home() { ToMoodTransition: () => ( ), - ToRecommendTransition: () => , OnboardingSurvey: () => ( ), - TodayMoodSurvey: () => ( - - ), + TodayMoodSurvey: () => , }; return
{pageMapping[currentPage]?.()}
; diff --git a/src/app/recommend/page.tsx b/src/app/recommend/page.tsx index 19affec..797eb40 100644 --- a/src/app/recommend/page.tsx +++ b/src/app/recommend/page.tsx @@ -6,9 +6,12 @@ import SideBar from "./_components/SideBar"; import SidePanel from "./_components/SidePanel"; import BackToSurveyButton from "./_components/BackToSurveyButton"; import MapView from "./_components/MapView"; +import TransitionScreen from "@/app/_components/TransitionScreen"; export default function RecommendPage() { const [spaceData, setSpaceData] = useState([]); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); useEffect(() => { const userId = localStorage.getItem("userId") || ""; @@ -26,9 +29,27 @@ export default function RecommendPage() { mood: onboarding[6], }; - fetchRecommendation(payload).then(setSpaceData); + setIsLoading(true); + setError(null); + + fetchRecommendation(payload) + .then((data) => { + setSpaceData(data); + }) + .catch((err) => { + console.error(err); + setError("추천 정보를 불러오는 데 실패했어요."); + }) + .finally(() => { + setIsLoading(false); + }); }, []); + if (isLoading) return ; + + // 에러 페이지 시안 완성되면 변경 + if (error) return
{error}
; + return (
diff --git a/src/lib/apis/survey.ts b/src/lib/apis/survey.ts index c6bfb98..65cca9f 100644 --- a/src/lib/apis/survey.ts +++ b/src/lib/apis/survey.ts @@ -8,7 +8,7 @@ export async function fetchRecommendation(payload: RecommendationRequest) { return res.data; } catch (err) { console.error("추천 API 실패:", err); - alert("추천 정보를 불러오는 데 실패했어요."); + throw err; } } @@ -18,6 +18,6 @@ export async function updateSatisfactionScore(payload: UpdateRequest) { await axios.post("/survey/update", payload); } catch (err) { console.error("만족도 API 호출 실패:", err); - alert("만족도 정보를 제출하는 데 실패했어요."); + throw err; } } From 3356bf09a88974a5e8312a009734e11152a845c6 Mon Sep 17 00:00:00 2001 From: hyeonjiroh Date: Tue, 8 Jul 2025 01:52:04 +0900 Subject: [PATCH 7/7] =?UTF-8?q?refactor:=20=EC=B6=94=EC=B2=9C=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EB=B6=88=EB=9F=AC=EC=98=A4=EB=8A=94=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=ED=9B=85=EC=9C=BC=EB=A1=9C=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_hooks/useSurveyRecommendation.ts | 44 +++++++++++++++++++ src/app/recommend/page.tsx | 39 +--------------- 2 files changed, 46 insertions(+), 37 deletions(-) create mode 100644 src/app/recommend/_hooks/useSurveyRecommendation.ts diff --git a/src/app/recommend/_hooks/useSurveyRecommendation.ts b/src/app/recommend/_hooks/useSurveyRecommendation.ts new file mode 100644 index 0000000..00ea439 --- /dev/null +++ b/src/app/recommend/_hooks/useSurveyRecommendation.ts @@ -0,0 +1,44 @@ +// hooks/useSurveyRecommendation.ts +import { useEffect, useState } from "react"; +import { fetchRecommendation } from "@/lib/apis/survey"; +import { RecommendationRequest, RecommendationResponse } from "@/lib/type"; + +export function useSurveyRecommendation() { + const [spaceData, setSpaceData] = useState([]); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + const userId = localStorage.getItem("userId") || ""; + const onboarding = JSON.parse( + localStorage.getItem("onboardingAnswers") ?? "[]" + ); + + const payload: RecommendationRequest = { + clientId: userId, + age: Number(onboarding[0]?.substr(0, 2) || 0), + gender: onboarding[1], + resident: onboarding[2], + city: onboarding[3], + want: onboarding[5], + mood: onboarding[6], + }; + + setIsLoading(true); + setError(null); + + fetchRecommendation(payload) + .then((data) => { + setSpaceData(data); + }) + .catch((err) => { + console.error(err); + setError("추천 정보를 불러오는 데 실패했어요."); + }) + .finally(() => { + setIsLoading(false); + }); + }, []); + + return { spaceData, isLoading, error }; +} diff --git a/src/app/recommend/page.tsx b/src/app/recommend/page.tsx index 797eb40..a05b774 100644 --- a/src/app/recommend/page.tsx +++ b/src/app/recommend/page.tsx @@ -1,49 +1,14 @@ "use client"; -import { useEffect, useState } from "react"; -import { fetchRecommendation } from "@/lib/apis/survey"; import SideBar from "./_components/SideBar"; import SidePanel from "./_components/SidePanel"; import BackToSurveyButton from "./_components/BackToSurveyButton"; import MapView from "./_components/MapView"; import TransitionScreen from "@/app/_components/TransitionScreen"; +import { useSurveyRecommendation } from "./_hooks/useSurveyRecommendation"; export default function RecommendPage() { - const [spaceData, setSpaceData] = useState([]); - const [isLoading, setIsLoading] = useState(true); - const [error, setError] = useState(null); - - useEffect(() => { - const userId = localStorage.getItem("userId") || ""; - const onboarding = JSON.parse( - localStorage.getItem("onboardingAnswers") ?? "[]" - ); - - const payload = { - clientId: userId, - age: Number(onboarding[0]?.substr(0, 2) || 0), - gender: onboarding[1], - resident: onboarding[2], - city: onboarding[3], - want: onboarding[5], - mood: onboarding[6], - }; - - setIsLoading(true); - setError(null); - - fetchRecommendation(payload) - .then((data) => { - setSpaceData(data); - }) - .catch((err) => { - console.error(err); - setError("추천 정보를 불러오는 데 실패했어요."); - }) - .finally(() => { - setIsLoading(false); - }); - }, []); + const { spaceData, isLoading, error } = useSurveyRecommendation(); if (isLoading) return ;