diff --git a/public/manifest.json b/public/manifest.json index 90256bc..1dfc38d 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -6,7 +6,6 @@ "display": "standalone", "background_color": "#ffffff", "theme_color": "#ffeeea", - "orientation": "portrait", "categories": [ "travel", "map", @@ -26,12 +25,5 @@ "type": "image/png", "purpose": "maskable any" } - ], - "prefer_related_applications": false, - "related_applications": [ - { - "platform": "webapp", - "url": "/manifest.json" - } ] } diff --git a/src/app/(pages)/course/[course_id]/page.tsx b/src/app/(pages)/course/[course_id]/page.tsx index ab99224..abf5e21 100644 --- a/src/app/(pages)/course/[course_id]/page.tsx +++ b/src/app/(pages)/course/[course_id]/page.tsx @@ -4,13 +4,17 @@ import { CourseDetail } from '../_components/course-detail'; import { CourseMap } from '../_components/course-map'; import { CourseDescription } from '../_components/course-description'; import { CourseRunwayPoint } from '../_components/course-runway-point'; -import { api } from '@/lib/api'; -import { getCourseAISummary, getCourseDetail } from '@/lib/api/courses'; +import { + getCourseAISummary, + getCourseDetail, + getUserCourseDetail, +} from '@/lib/api/courses'; import { Suspense } from 'react'; -import { Divide } from 'lucide-react'; import { LoadingSpinner } from '@/components/loading-spinner'; import MainPointLogo from '@/public/svg/logo/main-point-logo.svg'; import Link from 'next/link'; +import { cookies } from 'next/headers'; +import { Loader2 } from 'lucide-react'; interface CoursePageProps { params: Promise<{ course_id: string }>; @@ -19,7 +23,11 @@ interface CoursePageProps { export default async function CoursePage({ params }: CoursePageProps) { const { course_id } = await params; - const courseDetail = await getCourseDetail(course_id).then(res => res.data); + const cookieStore = await cookies(); + const token = cookieStore.get('accessToken')?.value; + const courseDetail = token + ? await getUserCourseDetail(course_id).then(res => res.data) + : await getCourseDetail(course_id).then(res => res.data); if (!courseDetail) { return ( @@ -45,6 +53,7 @@ export default async function CoursePage({ params }: CoursePageProps) {
@@ -59,7 +68,7 @@ export default async function CoursePage({ params }: CoursePageProps) { - +

코스 분석 요약을 불러오고 있어요.

} diff --git a/src/app/(pages)/course/_components/course-map.tsx b/src/app/(pages)/course/_components/course-map.tsx index 2938b95..f384e07 100644 --- a/src/app/(pages)/course/_components/course-map.tsx +++ b/src/app/(pages)/course/_components/course-map.tsx @@ -2,20 +2,27 @@ import { useState, useEffect } from 'react'; import GPXRouteMap from './gpx-parser-map'; +import { GPXParser } from '../_utils/gpx-parser'; export function CourseMap({ gpxUrl, crsKorNm, + isFavorite, }: { gpxUrl: string; crsKorNm: string; + isFavorite: boolean; }) { const [gpxContent, setGpxContent] = useState(''); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); - + const [startPosition, setStartPosition] = useState<{ + lat: number; + lng: number; + } | null>(null); useEffect(() => { localStorage.setItem('crsKorNm', crsKorNm); + localStorage.setItem('isFavorite', isFavorite.toString()); const fetchGpxContent = async () => { try { setIsLoading(true); @@ -32,8 +39,20 @@ export function CourseMap({ const content = await response.text(); setGpxContent(content); + + // GPX 파싱해서 시작점 좌표 추출 + try { + const track = GPXParser.parseGPX(content); + + if (track?.points && track.points.length > 0) { + const firstPoint = track.points[0]; + const position = { lat: firstPoint.lat, lng: firstPoint.lng }; + setStartPosition(position); + } + } catch (parseError) { + setError('GPX 파싱 오류'); + } } catch (err) { - console.error('GPX 파일 로드 실패:', err); setError('GPX 파일을 불러올 수 없습니다.'); } finally { setIsLoading(false); @@ -83,10 +102,11 @@ export function CourseMap({ startColor: '#00C851', endColor: '#FF6B6B', waypointColor: '#00C851', - size: 15, + size: 30, }} - waypointInterval={3} - showInfo={true} + waypointInterval={5} + showInfo={false} + customStartMarker={startPosition} /> )} diff --git a/src/app/(pages)/course/_components/course-runway-point.tsx b/src/app/(pages)/course/_components/course-runway-point.tsx index b3da0d8..4cec5e1 100644 --- a/src/app/(pages)/course/_components/course-runway-point.tsx +++ b/src/app/(pages)/course/_components/course-runway-point.tsx @@ -1,5 +1,4 @@ import { getCourseAISummary } from '@/lib/api/courses'; -import MainPointLogo from '@/public/svg/logo/main-point-logo.svg'; export async function CourseRunwayPoint({ course_id }: { course_id: string }) { const courseAISummary = await getCourseAISummary(course_id).then( diff --git a/src/app/(pages)/course/_components/course-surrond-tour/course-surrond-info.tsx b/src/app/(pages)/course/_components/course-surrond-tour/course-surrond-info.tsx index 5f33c89..eb3dfb2 100644 --- a/src/app/(pages)/course/_components/course-surrond-tour/course-surrond-info.tsx +++ b/src/app/(pages)/course/_components/course-surrond-tour/course-surrond-info.tsx @@ -105,7 +105,7 @@ export function CourseSurrondInfo() { 주변 정보 보기 diff --git a/src/app/(pages)/course/_components/gpx-parser-map.tsx b/src/app/(pages)/course/_components/gpx-parser-map.tsx index c18709c..1788118 100644 --- a/src/app/(pages)/course/_components/gpx-parser-map.tsx +++ b/src/app/(pages)/course/_components/gpx-parser-map.tsx @@ -104,9 +104,7 @@ const GPXRouteMap = ({ try { const parsedTrack = GPXParser.parseGPX(gpxContent); setTrack(parsedTrack); - } catch (err) { - console.error('GPX 파싱 오류:', err); - } + } catch (err) {} } else if (routePoints) { setTrack({ name: 'Custom Route', @@ -154,6 +152,10 @@ const GPXRouteMap = ({ logoControl: false, minZoom: 8, // 최소 줌 레벨 설정 maxZoom: 18, // 최대 줌 레벨 설정 + disableDoubleTapZoom: true, // 더블탭 줌 비활성화 + draggable: false, // 드래그 비활성화 + clickable: false, // 클릭 비활성화 + touchEnabled: false, // 터치 비활성화 }; const naverMap = new window.naver.maps.Map(mapRef.current, mapOptions); @@ -233,7 +235,6 @@ const GPXRouteMap = ({ // 커스텀 시작점 마커 if (customStartMarker) { - console.log('커스텀 마커 생성:', customStartMarker); const customMarker = new window.naver.maps.Marker({ position: new window.naver.maps.LatLng( customStartMarker.lat, diff --git a/src/app/(pages)/home/_components/course-list/ai-course.tsx b/src/app/(pages)/home/_components/course-list/ai-course.tsx index a09ef26..9ae5361 100644 --- a/src/app/(pages)/home/_components/course-list/ai-course.tsx +++ b/src/app/(pages)/home/_components/course-list/ai-course.tsx @@ -28,7 +28,7 @@ export function AICourse({ courses, isLoading }: AICourseProps) { {isLoading ? ( ) : ( -
+
{courses.map(course => ( - {`${title} + {imageUrl ? ( + {`${title} + ) : ( +
+ )}
diff --git a/src/app/(pages)/home/_components/course-list/popular-course.tsx b/src/app/(pages)/home/_components/course-list/popular-course.tsx index 4326543..7c11944 100644 --- a/src/app/(pages)/home/_components/course-list/popular-course.tsx +++ b/src/app/(pages)/home/_components/course-list/popular-course.tsx @@ -15,7 +15,7 @@ export function PopularCourse({ courses, isLoading }: PopularCourseProps) { {isLoading ? ( ) : ( -
+
{courses.map(course => ( 0) { const firstPoint = track.points[0]; const position = { lat: firstPoint.lat, lng: firstPoint.lng }; - console.log('시작점 좌표:', position); setStartPosition(position); } } catch (parseError) { - console.error('GPX 파싱 실패:', parseError); + setError('GPX 파싱 오류'); } } catch (err) { - console.error('GPX 파일 로드 실패:', err); setError('GPX 파일을 불러올 수 없습니다.'); } finally { setIsLoading(false); @@ -61,7 +58,7 @@ export function SearchCourseMap({ gpxUrl }: { gpxUrl: string }) { if (isLoading) { return ( -
+

경로를 불러오는 중...

diff --git a/src/app/(pages)/mypage/_components/place-pick-sheet.tsx b/src/app/(pages)/mypage/_components/place-pick-sheet.tsx index 51d5106..bda20ad 100644 --- a/src/app/(pages)/mypage/_components/place-pick-sheet.tsx +++ b/src/app/(pages)/mypage/_components/place-pick-sheet.tsx @@ -57,23 +57,10 @@ export function PlacePickSheet({ refetch: () => void; defaultIsPickPlace: string | null; }) { - const [viewportHeight, setViewportHeight] = useState(0); - - useEffect(() => { - const updateViewportHeight = () => { - setViewportHeight(window.innerHeight); - }; - - updateViewportHeight(); - window.addEventListener('resize', updateViewportHeight); - - return () => window.removeEventListener('resize', updateViewportHeight); - }, []); const [isActive, setIsActive] = useState('강원'); const [isPickPlace, setIsPickPlace] = useState(() => { if (!defaultIsPickPlace) return null; - - const foundPlace = findPlaceByName(defaultIsPickPlace); + const foundPlace = findPlaceByName(defaultIsPickPlace.split(' ')[1]); return foundPlace ?? { name: defaultIsPickPlace, type: '시' }; }); const scrollRef = useRef(null); @@ -106,7 +93,7 @@ export function PlacePickSheet({ await setDestination(destinationName); refetch(); toast.success('여행지 설정이 완료되었습니다.'); - setIsPickPlace(null); + setIsPickPlace(isPickPlace); setIsActive('강원'); } catch (error) { toast.error('여행지 설정에 실패했습니다.'); @@ -128,40 +115,29 @@ export function PlacePickSheet({ - - - { - setIsPickPlace( - defaultIsPickPlace - ? findPlaceByName(defaultIsPickPlace) - : null, - ); - }} - > - - - - + + + + 여행지 설정하기 + + + +
+

+ 여행, 어디로 떠나시나요? 완료하기 - - - -
-

- 여행, 어디로 떠나시나요?

{isPickPlace !== null ? ( @@ -179,7 +155,7 @@ export function PlacePickSheet({
-
+