Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions public/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#ffeeea",
"orientation": "portrait",
"categories": [
"travel",
"map",
Expand All @@ -26,12 +25,5 @@
"type": "image/png",
"purpose": "maskable any"
}
],
"prefer_related_applications": false,
"related_applications": [
{
"platform": "webapp",
"url": "/manifest.json"
}
]
}
19 changes: 14 additions & 5 deletions src/app/(pages)/course/[course_id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 }>;
Expand All @@ -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 (
Expand All @@ -45,6 +53,7 @@ export default async function CoursePage({ params }: CoursePageProps) {
<CourseMap
gpxUrl={courseDetail.gpxFilePath}
crsKorNm={courseDetail.crsKorNm}
isFavorite={courseDetail.isFavorite ?? false}
/>
<CourseDescription description={courseDetail.crsContents} />
<div className='flex-center px-5 pt-5'>
Expand All @@ -59,7 +68,7 @@ export default async function CoursePage({ params }: CoursePageProps) {
<Suspense
fallback={
<div className='flex-col-center h-full min-h-[160px] w-full min-w-[160px] gap-2'>
<LoadingSpinner />
<Loader2 className='text-point-400 size-12 animate-spin rounded-full' />
<p>코스 분석 요약을 불러오고 있어요.</p>
</div>
}
Expand Down
30 changes: 25 additions & 5 deletions src/app/(pages)/course/_components/course-map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<string>('');
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(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);
Expand All @@ -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);
Expand Down Expand Up @@ -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}
/>
)}
</div>
Expand Down
1 change: 0 additions & 1 deletion src/app/(pages)/course/_components/course-runway-point.tsx
Original file line number Diff line number Diff line change
@@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export function CourseSurrondInfo() {
주변 정보 보기
</SheetTrigger>
<SheetContent
side='right'
side='bottom'
className='mobile-area bg-gray-bg flex h-screen flex-col'
>
<SheetHeader className='border-gray-0 flex-shrink-0 border-b-8'>
Expand Down
9 changes: 5 additions & 4 deletions src/app/(pages)/course/_components/gpx-parser-map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/app/(pages)/home/_components/course-list/ai-course.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function AICourse({ courses, isLoading }: AICourseProps) {
{isLoading ? (
<CourseSkeleton />
) : (
<div className='scrollbar-hide flex gap-3 overflow-x-auto overflow-y-hidden'>
<div className='scrollbar-hide flex gap-3 overflow-x-auto overflow-y-hidden pr-4'>
{courses.map(course => (
<CourseCard
key={course.crsIdx}
Expand Down
20 changes: 12 additions & 8 deletions src/app/(pages)/home/_components/course-list/course-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,18 @@ export function CourseCard({
className='relative h-[196px] w-[168px] flex-shrink-0 cursor-pointer overflow-hidden rounded-[20px] transition-transform hover:scale-105'
onClick={handleClick}
>
<Image
src={imageUrl}
alt={`${title} 코스 이미지`}
fill
priority
sizes='100%'
className='object-cover'
/>
{imageUrl ? (
<Image
src={imageUrl}
alt={`${title} 코스 이미지`}
fill
priority
sizes='(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw'
className='object-cover'
/>
) : (
<div className='bg-gray-1 h-full w-full' />
)}

<div className='absolute inset-0 bg-gradient-to-t from-black/60 to-transparent' />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function PopularCourse({ courses, isLoading }: PopularCourseProps) {
{isLoading ? (
<CourseSkeleton />
) : (
<div className='scrollbar-hide flex gap-3 overflow-x-auto overflow-y-hidden'>
<div className='scrollbar-hide flex gap-3 overflow-x-auto overflow-y-hidden pr-4'>
{courses.map(course => (
<CourseCard
key={course.crsIdx}
Expand Down
7 changes: 2 additions & 5 deletions src/app/(pages)/home/_components/search/search-course-map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,16 @@ export function SearchCourseMap({ gpxUrl }: { gpxUrl: string }) {
// GPX 파싱해서 시작점 좌표 추출
try {
const track = GPXParser.parseGPX(content);
console.log('GPX 파싱 결과:', track);

if (track?.points && track.points.length > 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);
Expand All @@ -61,7 +58,7 @@ export function SearchCourseMap({ gpxUrl }: { gpxUrl: string }) {

if (isLoading) {
return (
<div className='flex flex-1 items-center justify-center bg-gray-100'>
<div className='bg-gray-1/80 flex h-full w-full flex-1 items-center justify-center'>
<div className='text-center'>
<div className='mx-auto mb-2 h-8 w-8 animate-spin rounded-full border-4 border-green-500 border-t-transparent'></div>
<p className='text-gray-600'>경로를 불러오는 중...</p>
Expand Down
54 changes: 15 additions & 39 deletions src/app/(pages)/mypage/_components/place-pick-sheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<ProvinceKey>('강원');
const [isPickPlace, setIsPickPlace] = useState<Place | null>(() => {
if (!defaultIsPickPlace) return null;

const foundPlace = findPlaceByName(defaultIsPickPlace);
const foundPlace = findPlaceByName(defaultIsPickPlace.split(' ')[1]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defaultIsPickPlace.split(' ')[1] 는 변수로 한번 정리해도 좋을 것 같습니다.

return foundPlace ?? { name: defaultIsPickPlace, type: '시' };
});
const scrollRef = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -106,7 +93,7 @@ export function PlacePickSheet({
await setDestination(destinationName);
refetch();
toast.success('여행지 설정이 완료되었습니다.');
setIsPickPlace(null);
setIsPickPlace(isPickPlace);
setIsActive('강원');
} catch (error) {
toast.error('여행지 설정에 실패했습니다.');
Expand All @@ -128,40 +115,29 @@ export function PlacePickSheet({
</SheetTrigger>
<SheetContent
side='bottom'
className={`mobile-area flex h-[${viewportHeight}px] max-w-[600px] flex-col`}
className={`mobile-area flex h-[80%] max-w-[600px] flex-col rounded-t-[28px]`}
>
<SheetHeader className='border-gray-0 flex-shrink-0 border-b-8'>
<SheetTitle className='flex h-13 w-full items-center justify-between px-4 py-2'>
<SheetClose
onClick={() => {
setIsPickPlace(
defaultIsPickPlace
? findPlaceByName(defaultIsPickPlace)
: null,
);
}}
>
<span className='flex-center size-13 px-2'>
<XIcon className='size-6' />
</span>
</SheetClose>
<SheetHeader className='border-gray-0 flex-shrink-0 border-b-8 pt-4'>
<span className='bg-gray-1 mx-auto h-2 w-[30%] rounded-full' />

<SheetTitle className='flex-center h-13 w-full px-4 py-2 pt-4'>
<span className='text-gray-bk text-[20px] leading-7 font-bold'>
여행지 설정하기
</span>
</SheetTitle>
</SheetHeader>

<div className='itmes-end border-gray-0 flex h-auto w-full flex-shrink-0 flex-col gap-3.5 border-b-8 px-6 pt-11 pb-7.5'>
<h1 className='font-extralight-medium text-gray-bk flex items-center justify-between text-[24px] leading-[33.6px]'>
여행, 어디로 떠나시나요?
<SheetClose>
<span
className='text-point-400 text-[14px] leading-[19.6px] font-bold'
className='text-point-400 text-[18px] leading-[19.6px] font-bold'
onClick={handlePlaceSubmit}
>
완료하기
</span>
</SheetClose>
</SheetTitle>
</SheetHeader>

<div className='itmes-end border-gray-0 flex h-auto w-full flex-shrink-0 flex-col gap-3.5 border-b-8 pt-11 pb-7.5 pl-6'>
<h1 className='font-extralight-medium text-gray-bk text-[24px] leading-[33.6px]'>
여행, 어디로 떠나시나요?
</h1>
<div className='custom-scrollbar flex items-center gap-2 overflow-x-auto pb-3'>
{isPickPlace !== null ? (
Expand All @@ -179,7 +155,7 @@ export function PlacePickSheet({
</div>
</div>

<section className='flex h-[calc(100vh-60px-177.6px)] w-full'>
<section className='flex h-[calc(100%-270px)] w-full'>
<aside className='bg-gray-0 scrollbar-hide flex h-auto max-w-28 flex-col items-center overflow-y-auto px-3 py-5'>
{REGION_LIST.map(item => (
<span
Expand Down
16 changes: 13 additions & 3 deletions src/app/(pages)/save/_components/course-card.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
'use client';

import { useRouter } from 'next/navigation';
import { cn } from '@/utils/cn';
import Image from 'next/image';

interface CourseCardProps {
title: string;
Expand All @@ -25,12 +28,19 @@ export function CourseCard({
return (
<div
className={cn(
'relative overflow-hidden rounded-2xl cursor-pointer transition-transform hover:scale-105',
className
'relative cursor-pointer overflow-hidden rounded-2xl transition-transform hover:scale-101',
className,
)}
onClick={handleClick}
>
<img src={imageUrl} alt={title} className='h-full w-full object-cover' />
<Image
src={imageUrl}
alt={title}
fill
className='h-full w-full object-cover'
priority
sizes='(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw'
/>
<div className='absolute right-0 bottom-0 left-0 bg-gradient-to-t from-black/60 to-transparent p-4'>
<h3 className='text-title2 text-white'>{title}</h3>
<p className='text-body4 text-white'>{location}</p>
Expand Down
2 changes: 1 addition & 1 deletion src/app/(pages)/save/_components/region-courses-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function RegionSection({ region, courses }: RegionSectionProps) {
return (
<div className='mb-8'>
<h2 className='text-title2 mb-3'>{region}</h2>
<div className='scrollbar-hide flex gap-3 overflow-x-auto'>
<div className='scrollbar-hide flex gap-3 overflow-x-auto overflow-y-hidden pr-6'>
{courses.map(course => (
<CourseCard
key={course.crsIdx}
Expand Down
Loading
Loading