diff --git a/app/create/page.tsx b/app/create/page.tsx
index 5714741..09bb220 100644
--- a/app/create/page.tsx
+++ b/app/create/page.tsx
@@ -145,12 +145,17 @@ export default function Page() {
// purposes를 localStorage에 저장 (장소 추천 카테고리로 사용)
const purposes = getPurposes();
if (purposes.length > 0) {
- // purposes 배열에서 장소 카테고리 추출 (마지막 값이 일반적으로 장소 카테고리)
- const category = purposes[purposes.length - 1];
- localStorage.setItem(`meeting_${meetingId}_category`, category);
- }
- if (meetingType) {
- localStorage.setItem(`meeting_${meetingId}_meetingType`, meetingType);
+ // meetingType 저장 (회의 또는 친목)
+ if (meetingType) {
+ localStorage.setItem(`meeting_${meetingId}_meetingType`, meetingType);
+ }
+
+ // 하위 카테고리 저장 (스터디 카페, 식당 등)
+ if (meetingType === '회의' && selectedLocation) {
+ localStorage.setItem(`meeting_${meetingId}_category`, selectedLocation);
+ } else if (meetingType === '친목' && selectedSocialPlace) {
+ localStorage.setItem(`meeting_${meetingId}_category`, selectedSocialPlace);
+ }
}
// 링크 공유 페이지 이동
@@ -312,8 +317,10 @@ export default function Page() {
>
-
-
{participantCount}
+
+ {participantCount}
명
-
+
{getDeadlineDate()}
-
+
{deadlineDays}
일
diff --git a/app/meeting/[id]/page.tsx b/app/meeting/[id]/page.tsx
index 1ce386e..8bff73d 100644
--- a/app/meeting/[id]/page.tsx
+++ b/app/meeting/[id]/page.tsx
@@ -314,7 +314,7 @@ export default function Page() {
diff --git a/app/recommend/page.tsx b/app/recommend/page.tsx
index 4af4a38..a9994cc 100644
--- a/app/recommend/page.tsx
+++ b/app/recommend/page.tsx
@@ -1,7 +1,7 @@
'use client';
import { useState, useMemo, Suspense } from 'react';
-import { useRouter, useSearchParams } from 'next/navigation';
+import { useRouter, useSearchParams } from 'next/navigation';
import Image from 'next/image';
import KakaoMapRecommend from '@/components/map/kakaoMapRecommend';
import { useRecommend } from '@/hooks/api/query/useRecommend';
@@ -15,6 +15,10 @@ function RecommendContent() {
const lat = searchParams.get('lat');
const lng = searchParams.get('lng');
+ // 🔥 쿼리스트링에서 카테고리 정보 읽기
+ const categoryFromUrl = searchParams.get('category') || '';
+ const meetingTypeFromUrl = searchParams.get('meetingType') as '회의' | '친목' | null;
+
// 좌표 파싱 (쿼리 파라미터에서 가져오기)
const midPlaceLatitude = lat ? parseFloat(lat) : undefined;
const midPlaceLongitude = lng ? parseFloat(lng) : undefined;
@@ -25,33 +29,45 @@ function RecommendContent() {
// 모임 정보 조회 (purposes 정보를 가져오기 위해)
const { data: meetingData } = useCheckMeeting(meetingId);
- // 상위 카테고리 추출 (API에서 가져오거나 localStorage에서)
+ // 🔥 상위 카테고리 추출 (우선순위: URL > API > localStorage)
const meetingType = useMemo(() => {
if (typeof window === 'undefined') return null;
-
- // 1. API에서 purposes 가져오기 (참여자도 접근 가능)
+
+ // 1. URL 쿼리스트링에서 가져오기 (최우선)
+ if (meetingTypeFromUrl === '회의' || meetingTypeFromUrl === '친목') {
+ localStorage.setItem(`meeting_${meetingId}_meetingType`, meetingTypeFromUrl);
+ return meetingTypeFromUrl;
+ }
+
+ // 2. API에서 purposes 가져오기 (참여자도 접근 가능)
if (meetingData?.data?.purposes && meetingData.data.purposes.length > 0) {
const firstPurpose = meetingData.data.purposes[0];
if (firstPurpose === '회의' || firstPurpose === '친목') {
- // localStorage에도 저장 (다음 접근 시 빠르게 사용) localStorage.setItem(`meeting_${meetingId}_meetingType`, firstPurpose);
+ localStorage.setItem(`meeting_${meetingId}_meetingType`, firstPurpose);
return firstPurpose as '회의' | '친목';
}
}
-
-
+
+ // 3. localStorage에서 가져오기
const cachedType = localStorage.getItem(`meeting_${meetingId}_meetingType`);
if (cachedType === '회의' || cachedType === '친목') {
return cachedType as '회의' | '친목';
}
-
+
return null;
- }, [meetingId, meetingData]);
+ }, [meetingId, meetingData, meetingTypeFromUrl]);
- // 하위 카테고리 추출 (API에서 가져오거나 localStorage에서)
+ // 🔥 하위 카테고리 추출 (우선순위: URL > API > localStorage)
const defaultCategory = useMemo(() => {
if (typeof window === 'undefined') return '';
-
- // 1. API에서 가져온 purposes의 마지막 값 사용
+
+ // 1. URL 쿼리스트링에서 가져오기 (최우선)
+ if (categoryFromUrl) {
+ localStorage.setItem(`meeting_${meetingId}_category`, categoryFromUrl);
+ return categoryFromUrl;
+ }
+
+ // 2. API에서 가져온 purposes의 마지막 값 사용
if (meetingData?.data?.purposes && meetingData.data.purposes.length > 1) {
const subCategory = meetingData.data.purposes[meetingData.data.purposes.length - 1];
if (subCategory) {
@@ -60,18 +76,22 @@ function RecommendContent() {
return subCategory;
}
}
-
+
+ // 3. localStorage에서 가져오기
const cachedCategory = localStorage.getItem(`meeting_${meetingId}_category`);
return cachedCategory || '';
- }, [meetingId, meetingData]);
+ }, [meetingId, meetingData, categoryFromUrl]);
const [selectedCategory, setSelectedCategory] = useState
(() => {
- if (typeof window === 'undefined') return '';
- return localStorage.getItem(`meeting_${meetingId}_category`) || '';
+ if (typeof window !== 'undefined') {
+ const cachedCategory = localStorage.getItem(`meeting_${meetingId}_category`);
+ if (cachedCategory) return cachedCategory;
+ }
+ return '';
});
const currentCategory = selectedCategory || defaultCategory;
-
+
const effectiveCategory = currentCategory;
// 카테고리 변경 핸들러
@@ -84,7 +104,11 @@ function RecommendContent() {
};
// 장소 추천 API 호출 (effectiveCategory 사용 - selectedCategory가 우선)
- const { data: recommendData, isLoading, isError } = useRecommend({
+ const {
+ data: recommendData,
+ isLoading,
+ isError,
+ } = useRecommend({
meetingId,
midPlace,
category: effectiveCategory,
@@ -134,7 +158,7 @@ function RecommendContent() {
- {midPlace} 주변 장소 추천
+ {midPlace}역 주변 장소 추천
{/* 모바일 전용 지도 (작게 표시) */}
diff --git a/app/result/[id]/page.tsx b/app/result/[id]/page.tsx
index f7b10a4..45a99c3 100644
--- a/app/result/[id]/page.tsx
+++ b/app/result/[id]/page.tsx
@@ -6,6 +6,7 @@ import { useOpenModal } from '@/hooks/useOpenModal';
import { useParams, useRouter } from 'next/navigation';
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';
export default function Page() {
@@ -21,6 +22,7 @@ export default function Page() {
});
const { data: midpointData, isLoading, isError } = useMidpoint(id);
+ const { data: meetingData } = useCheckMeeting(id);
const locationResults = useMemo(() => {
if (!midpointData?.success || !midpointData.data || !Array.isArray(midpointData.data)) {
@@ -30,7 +32,7 @@ export default function Page() {
return midpointData.data.map((midpoint, index) => {
const { endStation, endStationLine, userRoutes } = midpoint;
const myRoute = userRoutes.find((route) => route.nickname === myNickname);
- const travelTime = myRoute?.travelTime || 0; // 기본값 0 설정
+ const travelTime = myRoute?.travelTime || 0;
// 호선 번호 추출 함수 (숫자가 있으면 숫자만, 없으면 앞 글자만)
const extractLineNumber = (linenumber: string): string => {
@@ -63,8 +65,8 @@ export default function Page() {
const lineNumber = extractLineNumber(path.linenumber);
if (lineNumber) {
transferPathLines.push({
- display: lineNumber, // 원 안에 표시할 값
- text: path.linenumber, // 텍스트로 표시할 원래 값
+ display: lineNumber,
+ text: path.linenumber,
});
}
}
@@ -74,12 +76,11 @@ export default function Page() {
if (endStationLine) {
const endLineNumber = extractLineNumber(endStationLine);
if (endLineNumber) {
- // transferPathLines의 마지막 항목과 비교
const lastLine = transferPathLines[transferPathLines.length - 1];
if (lastLine?.display !== endLineNumber) {
transferPathLines.push({
- display: endLineNumber, // 원 안에 표시할 값
- text: endStationLine, // 텍스트로 표시할 원래 값
+ display: endLineNumber,
+ text: endStationLine,
});
}
}
@@ -112,23 +113,23 @@ export default function Page() {
if (/^\d+$/.test(cleaned)) {
switch (cleaned) {
case '1':
- return 'bg-[#004A85]'; // 1호선 파랑
+ return 'bg-[#004A85]';
case '2':
- return 'bg-[#00A23F]'; // 2호선 초록
+ return 'bg-[#00A23F]';
case '3':
- return 'bg-[#ED6C00]'; // 3호선 파랑
+ return 'bg-[#ED6C00]';
case '4':
- return 'bg-[#009BCE]'; // 4호선 파랑
+ return 'bg-[#009BCE]';
case '5':
- return 'bg-[#794698]'; // 5호선 보라색
+ return 'bg-[#794698]';
case '6':
- return 'bg-[#7C4932]'; // 6호선 빨강
+ return 'bg-[#7C4932]';
case '7':
- return 'bg-[#6E7E31]'; // 7호선 초록
+ return 'bg-[#6E7E31]';
case '8':
- return 'bg-[#D11D70]'; // 8호선 빨강
+ return 'bg-[#D11D70]';
case '9':
- return 'bg-[#A49D87]'; // 9호선 회색
+ return 'bg-[#A49D87]';
default:
return 'bg-gray-400';
}
@@ -136,41 +137,35 @@ export default function Page() {
// 전체 호선명으로 처리 (앞 글자가 겹치는 경우 구분)
switch (fullLineName) {
- // 수도권 도시철도(경전철)
case '우이신설선':
- return 'bg-[#B0CE18]'; // 우이신설 노랑
+ return 'bg-[#B0CE18]';
case '신림선':
- return 'bg-[#5E7DBB]'; // 신림선 하늘
+ return 'bg-[#5E7DBB]';
case '의정부경전철':
- return 'bg-[#F0831E]'; // 의정부경전철 주황
+ return 'bg-[#F0831E]';
case '용인에버라인':
- return 'bg-[#44A436]'; // 용인에버라인 초록
+ return 'bg-[#44A436]';
case '인천2호선':
- return 'bg-[#F4A462]'; // 인천2호선 살색
+ return 'bg-[#F4A462]';
case '김포골드라인':
- return 'bg-[#F4A462]'; // 김포골드라인 금색
-
- // 수도권 도시철도(중전철)
+ return 'bg-[#F4A462]';
case '경의선':
case '경의중앙선':
- return 'bg-[#6AC2B3]'; // 경의중앙선 민트색
+ return 'bg-[#6AC2B3]';
case '수인분당선':
- return 'bg-[#ECA300]'; // 수인분당선 노란색
+ return 'bg-[#ECA300]';
case '신분당선':
- return 'bg-[#B81B30]'; // 신분당선 빨강색
+ return 'bg-[#B81B30]';
case '인천1호선':
- return 'bg-[#B4C7E7]'; // 인천1호선 연한 하늘색
+ return 'bg-[#B4C7E7]';
case '공항철도':
- return 'bg-[#0079AC]'; // 공항철도 파랑색
-
- // 광역철도
+ return 'bg-[#0079AC]';
case '경춘선':
- return 'bg-[#007A62]'; // 경춘선 초록
+ return 'bg-[#007A62]';
case '경강산':
- return 'bg-[#0B318F]'; // 경강산 파란
+ return 'bg-[#0B318F]';
case '서해선':
- return 'bg-[#5EAC41]'; // 서해선 초록
-
+ return 'bg-[#5EAC41]';
default:
return 'bg-gray-400';
}
@@ -214,6 +209,7 @@ export default function Page() {
}}
userRoutes={selectedResult.userRoutes}
meetingId={id}
+ purposes={meetingData?.data?.purposes}
/>
);
@@ -338,6 +334,7 @@ export default function Page() {
}}
userRoutes={selectedResult.userRoutes}
meetingId={id}
+ purposes={meetingData?.data?.purposes}
/>
);
})()}
diff --git a/components/join/joinForm.tsx b/components/join/joinForm.tsx
index 86e3857..871fa0c 100644
--- a/components/join/joinForm.tsx
+++ b/components/join/joinForm.tsx
@@ -1,6 +1,6 @@
'use client';
-import { useRouter } from 'next/navigation';
+import { useRouter, useSearchParams } from 'next/navigation'; // [추가] useSearchParams
import { useState, useEffect } from 'react';
import { useEnterParticipant } from '@/hooks/api/mutation/useEnterParticipant';
import { useToast } from '@/hooks/useToast';
@@ -14,6 +14,7 @@ interface JoinFormProps {
export default function JoinForm({ meetingId }: JoinFormProps) {
const router = useRouter();
+ const searchParams = useSearchParams(); // [추가] 쿼리 스트링 읽기용 훅
// meetingId는 부모(Page)에서 props로 전달받음
const { isLogin, isChecking } = useIsLoggedIn(meetingId);
@@ -21,11 +22,28 @@ export default function JoinForm({ meetingId }: JoinFormProps) {
const [name, setName] = useState('');
const [password, setPassword] = useState('');
const [isRemembered, setIsRemembered] = useState(true);
- const [errorMessage, setErrorMessage] = useState('');
+ const [errorMessage, setErrorMessage] = useState(''); // [수정] string 타입으로 초기화
const participantEnter = useEnterParticipant();
const { isVisible, show } = useToast();
+ // [추가] 공유 링크로 들어왔을 때 카테고리 정보를 localStorage에 저장
+ useEffect(() => {
+ if (!meetingId) return;
+
+ const meetingType = searchParams.get('meetingType');
+ const category = searchParams.get('category');
+
+ // 값이 존재할 때만 저장 (기존 값을 덮어쓰거나 새로 저장)
+ if (meetingType) {
+ localStorage.setItem(`meeting_${meetingId}_meetingType`, meetingType);
+ }
+ if (category) {
+ localStorage.setItem(`meeting_${meetingId}_category`, category);
+ }
+ }, [searchParams, meetingId]);
+
+ // 기존 로그인 체크 및 리다이렉트 로직
useEffect(() => {
if (isChecking) return;
@@ -37,8 +55,8 @@ export default function JoinForm({ meetingId }: JoinFormProps) {
if (isChecking || isLogin) {
return (
-
-
로그인 정보를 확인 중...
+
+
로그인 정보를 확인 중...
);
}
@@ -50,6 +68,7 @@ export default function JoinForm({ meetingId }: JoinFormProps) {
if (!isFormValid || !meetingId) return;
try {
+ // @ts-ignore (혹시 모를 타입 불일치 방지, API 스펙에 따라 제거 가능)
const result = await participantEnter.mutateAsync({
meetingId,
data: {
@@ -65,7 +84,7 @@ export default function JoinForm({ meetingId }: JoinFormProps) {
setErrorMessage('모임 참여에 실패했습니다. 다시 시도해주세요.');
show();
}
- } catch {
+ } catch (error) {
setErrorMessage('모임 참여에 실패했습니다. 이름과 비밀번호를 확인해주세요.');
show();
}
@@ -78,7 +97,6 @@ export default function JoinForm({ meetingId }: JoinFormProps) {