diff --git a/app/favicon.ico b/app/favicon.ico index 813d289..0bd0e29 100644 Binary files a/app/favicon.ico and b/app/favicon.ico differ diff --git a/app/result/[id]/page.tsx b/app/result/[id]/page.tsx index 45a99c3..9396615 100644 --- a/app/result/[id]/page.tsx +++ b/app/result/[id]/page.tsx @@ -8,8 +8,10 @@ import KakaoMapLine from '@/components/map/kakaoMapLine'; import { useMidpoint } from '@/hooks/api/query/useMidpoint'; import { useCheckMeeting } from '@/hooks/api/query/useCheckMeeting'; import { getMeetingUserId } from '@/lib/storage'; +import { useQueryClient } from '@tanstack/react-query'; export default function Page() { + const queryClient = useQueryClient(); const openModal = useOpenModal(); const router = useRouter(); const params = useParams(); @@ -103,6 +105,9 @@ export default function Page() { const [selectedResultId, setSelectedResultId] = useState(1); const handleModifyStart = () => { + queryClient.removeQueries({ queryKey: ['midpoint', id] }); + queryClient.removeQueries({ queryKey: ['recommend', id] }); + router.back(); }; diff --git a/components/join/joinForm.tsx b/components/join/joinForm.tsx index 871fa0c..a1da9ce 100644 --- a/components/join/joinForm.tsx +++ b/components/join/joinForm.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useRouter, useSearchParams } from 'next/navigation'; // [추가] useSearchParams +import { useRouter, useSearchParams } from 'next/navigation'; import { useState, useEffect } from 'react'; import { useEnterParticipant } from '@/hooks/api/mutation/useEnterParticipant'; import { useToast } from '@/hooks/useToast'; @@ -14,7 +14,7 @@ interface JoinFormProps { export default function JoinForm({ meetingId }: JoinFormProps) { const router = useRouter(); - const searchParams = useSearchParams(); // [추가] 쿼리 스트링 읽기용 훅 + const searchParams = useSearchParams(); // meetingId는 부모(Page)에서 props로 전달받음 const { isLogin, isChecking } = useIsLoggedIn(meetingId); @@ -22,7 +22,7 @@ export default function JoinForm({ meetingId }: JoinFormProps) { const [name, setName] = useState(''); const [password, setPassword] = useState(''); const [isRemembered, setIsRemembered] = useState(true); - const [errorMessage, setErrorMessage] = useState(''); // [수정] string 타입으로 초기화 + const [errorMessage, setErrorMessage] = useState(''); const participantEnter = useEnterParticipant(); const { isVisible, show } = useToast(); @@ -68,7 +68,7 @@ export default function JoinForm({ meetingId }: JoinFormProps) { if (!isFormValid || !meetingId) return; try { - // @ts-ignore (혹시 모를 타입 불일치 방지, API 스펙에 따라 제거 가능) + // @ts-ignore const result = await participantEnter.mutateAsync({ meetingId, data: { @@ -77,15 +77,24 @@ export default function JoinForm({ meetingId }: JoinFormProps) { }, }); + // 1. HTTP 200 OK지만 논리적 실패인 경우 (success: false) if (result.success) { setMeetingUserId(meetingId, name, isRemembered); router.push(`/meeting/${meetingId}`); } else { - setErrorMessage('모임 참여에 실패했습니다. 다시 시도해주세요.'); + setErrorMessage(result.data.message || '모임 참여에 실패했습니다. 다시 시도해주세요.'); show(); } - } catch (error) { - setErrorMessage('모임 참여에 실패했습니다. 이름과 비밀번호를 확인해주세요.'); + } catch (error: any) { + const errorData = error.data || error.response?.data; + const serverMessage = errorData?.message; + + if (serverMessage) { + setErrorMessage(serverMessage); + } else { + setErrorMessage('모임 참여에 실패했습니다. 다시 시도해주세요.'); + } + show(); } }; diff --git a/components/map/kakaoMapLine.tsx b/components/map/kakaoMapLine.tsx index fcd34db..14627ef 100644 --- a/components/map/kakaoMapLine.tsx +++ b/components/map/kakaoMapLine.tsx @@ -52,7 +52,6 @@ export default function KakaoMapLine({ }: KakaoMapLineProps) { const router = useRouter(); const [map, setMap] = useState(null); - const [hoveredUserId, setHoveredUserId] = useState(null); useEffect(() => { if (!map || !endStation || userRoutes.length === 0) return; @@ -83,13 +82,11 @@ export default function KakaoMapLine({ let meetingType = ''; let category = ''; - // 🔥 1순위: localStorage에서 가져오기 if (typeof window !== 'undefined') { meetingType = localStorage.getItem(`meeting_${meetingId}_meetingType`) || ''; category = localStorage.getItem(`meeting_${meetingId}_category`) || ''; } - // 🔥 2순위: localStorage에 없으면 purposes에서 가져오기 (fallback) if (!meetingType && purposes && purposes.length > 0) { meetingType = purposes[0]; } @@ -97,9 +94,6 @@ export default function KakaoMapLine({ category = purposes[purposes.length - 1]; } - console.log('🔍 meetingType:', meetingType); - console.log('🔍 category:', category); - const params = new URLSearchParams({ meetingId, midPlace: endStation.name, @@ -107,14 +101,9 @@ export default function KakaoMapLine({ lng: endStation.longitude.toString(), }); - if (meetingType) { - params.append('meetingType', meetingType); - } - if (category) { - params.append('category', category); - } + if (meetingType) params.append('meetingType', meetingType); + if (category) params.append('category', category); - console.log('🔍 final URL:', `/recommend?${params.toString()}`); router.push(`/recommend?${params.toString()}`); }; @@ -136,10 +125,11 @@ export default function KakaoMapLine({ level={8} onCreate={setMap} > + {/* 도착지 마커 */}
{endStation.name} @@ -147,7 +137,6 @@ export default function KakaoMapLine({ {userRoutes.map((userRoute, index) => { - const isHovered = hoveredUserId === userRoute.nickname; const userColor = getRandomHexColor(userRoute.nickname); const offsetMultiplier = index - (userRoutes.length - 1) / 2; @@ -181,36 +170,32 @@ export default function KakaoMapLine({ /> )} - -
setHoveredUserId(userRoute.nickname)} - onMouseLeave={() => setHoveredUserId(null)} - > -
- - {userRoute.startStation} ({userRoute.travelTime}분) + {/* 출발지 마커 & 정보창 (항상 표시) */} + +
+ {/* 1. 상단 정보 말풍선 (검은색 박스) */} +
+ + {userRoute.startStation}역에서 + + + {userRoute.travelTime}분 -
+ + {/* 말풍선 꼬리 (아래쪽 화살표) */} +
+ {/* 2. 하단 원형 프로필 아이콘 */}
- + {userRoute.nickname.charAt(0)}
@@ -223,7 +208,7 @@ export default function KakaoMapLine({