PageSourceSearch

https://hanttrail-8fwxhbgl.manus.space/assets/SaramgilCourseDetail-KK0kmkyL.js

js hanttrail-8fwxhbgl.manus.space collected 2026-10-03 05:03:32 UTC 13,446 bytes, 1 lines download raw bytes

1import{H,W as Q,q as V,r,s as G,j as e,G as J,B as U,Y as Z,t as B}from"./index-CqGqwWKp.js";import{B as ee}from"./badge-CajhVRbo.js";import{M as ae}from"./Map-BElKnxci.js";import{i as se,g as te,a as re}from"./trackingGuard-Bochp0Er.js";import{W as le}from"./WeatherAirWidget-BOMDzfI-.js";import{t as ie}from"./subscriptionPlans-BhNHOzcV.js";import{C as ce}from"./chevron-left-BVmVB8Vs.js";import{M as $}from"./map-pin-DifvMV2M.js";import{C as oe}from"./clock-Sbq_3bEj.js";import{M as ne}from"./mountain-D3M_wSpQ.js";import{I as de}from"./info-BAYaVzoF.js";import{P as ge}from"./play-Hbmy7Cz5.js";import"./usePersistFn-DaDCSoQ3.js";const _={easy:"쉬움",moderate:"보통",hard:"어려움"},me={easy:"bg-green-100 text-green-700",moderate:"bg-yellow-100 text-yellow-700",hard:"bg-red-100 text-red-700"};function xe(n){const g=Math.floor(n/60),m=n%60;return g===0?`${m}분`:m===0?`${g}시간`:`${g}시간 ${m}분`}async function ue(n,g){const m=`/api/proxy-gpx?url=${encodeURIComponent(n)}`,x=await fetch(m,{signal:g});if(!x.ok)throw new Error("GPX 로드 실패");const S=await x.text(),v=new DOMParser().parseFromString(S,"application/xml").querySelectorAll("trkseg"),p=[];return v.forEach(D=>{const f=Array.from(D.querySelectorAll("trkpt")).map(i=>({lat:parseFloat(i.getAttribute("lat")??"0"),lng:parseFloat(i.getAttribute("lon")??"0")})).filter(i=>i.lat!==0&&i.lng!==0);f.length>0&&p.push(f)}),p}function Pe(){const[,n]=H(),g=Q(),{user:m}=V(),x=r.useRef(null),S=r.useRef(!1),[u,T]=r.useState([]),[v,p]=r.useState(!1),[D,f]=r.useState(null),i=r.useRef([]),E=r.useRef([]);E.current=u;const o=new URLSearchParams(g),O=o.get("id")??"",C=o.get("name")??"",t=o.get("gpxUrl")??"",M=o.get("distanceKm")?parseFloat(o.get("distanceKm")):null,R=o.get("durationMin")?parseInt(o.get("durationMin")):null,h=o.get("difficulty")??"",L=o.get("description")??"",b=o.get("returnPath")??"/saramgil",j=Number(O),A=Number.isInteger(j)&&j>0,W=b.includes("seoul-dulegil"),{data:N,isLoading:K,isError:I}=G.saramgil.getTrack.useQuery({id:j},{enabled:!t&&A,staleTime:300*1e3}),k=!!t||!!N?.points?.length;r.useEffect(()=>{if(!t&&!N?.points?.length)return;const s=new AbortController;let l=!1;return p(!0),f(null),(t?ue(t,s.signal):Promise.resolve([N.points.map(a=>({lat:a.lat,lng:a.lng}))])).then(a=>{l||(T(a),p(!1))}).catch(a=>{l||a instanceof DOMException&&a.name==="AbortError"||(f("GPX 파일을 불러오지 못했습니다."),p(!1))}),()=>{l=!0,s.abort()}},[t,N]),r.useEffect(()=>{!t&&I&&(p(!1),f("공식 트랙 좌표를 불러오지 못했습니다."))},[t,I]);const y=r.useCallback((s,l)=>{if(i.current.forEach(c=>{try{c.setMap(null)}catch{}}),i.current=[],l.length===0)return;const d=window.google?.maps;if(!d)return;const a=[];if(l.forEach(c=>{const w=c.map(F=>new d.LatLng(F.lat,F.lng));a.push(...w);const Y=new d.Polyline({path:w,geodesic:!0,strokeColor:"#10b981",strokeOpacity:.9,strokeWeight:4,map:s});i.current.push(Y)}),a.length>0){const c=new d.LatLngBounds;a.forEach(w=>c.extend(w)),s.fitBounds(c,{top:40,bottom:40,left:40,right:40})}},[]),X=r.useCallback(s=>{x.current=s,S.current=!0;const l=E.current;l.length>0&&setTimeout(()=>y(s,l),100)},[y]);r.useEffect(()=>{if(!S.current||!x.current||u.length===0)return;const s=x.current,l=setTimeout(()=>{y(s,u)},100);return()=>clearTimeout(l)},[u,y]),r.useEffect(()=>()=>{i.current.forEach(s=>{try{s.setMap(null)}catch{}}),i.current=[],x.current=null,S.current=!1},[]);const{data:q}=G.subscription.myStatus.useQuery(void 0,{enabled:!!m});q?.planTier;const P=u.flat()[0],z=async()=>{if(!t&&!A)return;if(se()){B.error(`현재 '${te()}' 기록 중입니다. 먼저 트래킹을 종료해 주세요.`,{duration:4e3});return}const s=u.flat();if(s.length>0){const c=await re(s);if(c.tooFar){B.error(`현재 위치가 해당 코스와 약 ${c.distKm}km 떨어져 있습니다. 해당 지역에서 따라가기를 시작해 주세요.`,{duration:5e3});return}}const d=[["seoul-dulegil","seoul-dulegil"],["ganghwa","ganghwa-nadeulgil"],["seongnam","seongnam-nubigil"],["korea-dulegil","korea-dulegil"],["forest50","forest50-stamp"]].find(([c])=>b.includes(c))?.[1],a=new URLSearchParams({courseName:C,returnPath:b});t?a.set("externalGpxUrl",t):a.set("saramgilTrailId",String(j)),d&&a.set("trailTag",d),n(`/track?${a.toString()}`)};return e.jsxs("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:226",className:"min-h-screen bg-gray-50",children:[e.jsx("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:228",className:"bg-white border-b sticky top-0 z-10",children:e.jsxs("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:229",className:"flex items-center gap-3 px-4 py-3",children:[e.jsx("button",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:230",onClick:()=>n(b),className:"p-1 rounded-full hover:bg-gray-100",children:e.jsx(ce,{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:234",className:"w-5 h-5 text-gray-600"})}),e.jsxs("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:236",className:"flex-1 min-w-0",children:[e.jsx("h1",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:237",className:"text-base font-bold text-gray-900 truncate",children:C||"코스 상세"}),e.jsx("p",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:238",className:"text-xs text-gray-500",children:"사람길 트래킹"})]}),h&&e.jsx(ee,{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:241",className:`text-xs ${me[h]??""}`,variant:"secondary",children:_[h]??h}
1)]})}),e.jsx("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:252",className:"relative bg-gray-200",style:{height:"280px"},children:k?e.jsxs(e.Fragment,{children:[e.jsx(ae,{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:255",onMapReady:X,className:"w-full h-full",gestureHandling:"greedy"}),v&&e.jsx("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:261",className:"absolute inset-0 flex items-center justify-center bg-white/60",children:e.jsx("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:262",className:"text-sm text-gray-500 animate-pulse",children:"경로 불러오는 중..."})}),D&&e.jsx("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:266",className:"absolute bottom-3 left-1/2 -translate-x-1/2 bg-red-50 border border-red-200 rounded-lg px-4 py-2 text-xs text-red-600",children:D})]}):e.jsx("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:272",className:"flex items-center justify-center h-full",children:e.jsxs("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:273",className:"text-center text-gray-400",children:[e.jsx($,{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:274",className:"w-10 h-10 mx-auto mb-2 opacity-40"}),e.jsx("p",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:275",className:"text-sm",children:"GPX 파일이 없습니다"})]})})}),e.jsxs("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:282",className:"px-4 py-4 space-y-4",children:[e.jsxs("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:284",className:"bg-white rounded-xl border border-gray-100 shadow-sm p-4",children:[e.jsx("h2",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:285",className:"font-bold text-gray-900 text-base mb-3",children:C}),e.jsxs("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:286",className:"flex flex-wrap gap-4 text-sm text-gray-600",children:[M!==null&&e.jsxs("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:288",className:"flex items-center gap-1.5",children:[e.jsx($,{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:289",className:"w-4 h-4 text-emerald-500"}),e.jsxs("span",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:290",className:"font-medium",children:[M.toFixed(1)," km"]})]}),R!==null&&e.jsxs("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:294",className:"flex items-center gap-1.5",children:[e.jsx(oe,{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:295",className:"w-4 h-4 text-blue-500"}),e.jsx("span",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:296",className:"font-medium",children:xe(R)})]}),h&&e.jsxs("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:300",className:"flex items-center gap-1.5",children:[e.jsx(ne,{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:301",className:"w-4 h-4 text-orange-400"}),e.jsx("span",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:302",className:"font-medium",children:_[h]??h})]})]})]}),L&&e.jsxs("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:310",className:"bg-white rounded-xl border border-gray-100 shadow-sm p-4",children:[e.jsxs("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:311",className:"flex items-center gap-2 mb-2",children:[e.jsx(de,{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:312",className:"w-4 h-4 text-emerald-600"}),e.jsx("h3",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:313",className:"font-semibold text-gray-800 text-sm",children:"코스 소개"})]}),e.jsx("p",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:315",className:"text-sm text-gray-600 leading-relaxed whitespace-pre-line",children:L})]}),W&&e.jsx("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:322",className:"rounded-xl border border-emerald-200 bg-emerald-50 p-4",children:e.jsxs("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:323",className:"flex items-start gap-2.5",children:[e.jsx("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:324",className:"mt-0.5 rounded-lg bg-emerald-100 p-2 text-emerald-700",children:e.jsx(J,{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:325",className:"h-4 w-4"})}),e.jsxs("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:327",className:"min-w-0",children:[e.jsx("h3",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:328",className:"text-sm font-bold text-emerald-900",children:"서울둘레길 스탬프 인증 안내"}),e.jsxs("ol",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:329",className:"mt-2 space-y-1 text-xs leading-relaxed text-emerald-800",children:[e.jsxs("li",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:330",children:[e.jsx("strong",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:330",children:"1."})," 이 코스에서 ",e.jsx("strong",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:330",children:"따라가기"}),"를 시작합니다."]}),e.jsxs("li",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:331",children:[e.jsx("strong",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:331",children:"2."})," 스탬프 위치 반경에 들어오면 지도·음성으로 위치 안내가 나타납니다."]}),e.jsxs("li",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:332",children:[e.jsx("strong",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:332",children:"3."})," 안내 팝업의 ",e.jsx("strong",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:332",children:"스탬프북 바로가기"}
1),"에서 GPS 위치를 확인해 도장을 찍습니다."]})]}),e.jsx("p",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:334",className:"mt-2 text-[11px] leading-relaxed text-emerald-700",children:"위치 안내만으로는 스탬프가 자동 저장되지 않으며, 스탬프북에서 직접 확인해야 기록됩니다."}),e.jsx("button",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:335",type:"button",onClick:()=>n("/stamp-book/seoul-dulegil"),className:"mt-3 inline-flex items-center gap-1 text-xs font-semibold text-emerald-800 underline underline-offset-2",children:"스탬프북 열기"})]})]})}),P&&e.jsx("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:349",children:ie()?e.jsx(le,{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:351",lat:P.lat,lng:P.lng,locationLabel:C,showWeekly:!0}):e.jsxs("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:358",className:"bg-white rounded-xl border border-gray-100 shadow-sm p-4 flex items-center gap-3",children:[e.jsx("span",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:359",className:"text-2xl",children:"🔒"}),e.jsxs("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:360",children:[e.jsx("p",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:361",className:"text-sm font-semibold text-gray-800",children:"날씨 · 공기질 · 주간 예보"}),e.jsx("p",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:362",className:"text-xs text-gray-500 mt-0.5",children:"프리미엄 이상 구독 시 이용 가능합니다"})]})]})}),e.jsxs("div",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:370",className:"flex gap-3 pb-6",children:[e.jsxs(U,{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:371",onClick:z,disabled:!k,className:"flex-1 bg-emerald-600 hover:bg-emerald-700 text-white font-semibold",size:"lg",children:[e.jsx(ge,{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:377",className:"w-4 h-4 mr-2"}),k?"따라가기":K?"경로 불러오는 중":"GPX 준비 중"]}),t&&e.jsx(U,{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:381",asChild:!0,variant:"outline",size:"lg",className:"shrink-0 border-emerald-200 text-emerald-700 hover:bg-emerald-50",children:e.jsx("a",{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:387",href:t,download:`${C}.gpx`,target:"_blank",rel:"noopener noreferrer",children:e.jsx(Z,{"data-loc":"client/src/pages/SaramgilCourseDetail.tsx:393",className:"w-4 h-4"})})})]})]})]})}export{Pe as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.