PageSourceSearch

https://lesvacances.co.kr/assets/WishlistPage-2vp7AUyU.js

js lesvacances.co.kr collected 2026-10-03 01:24:19 UTC 13,611 bytes, 1 lines download raw bytes

1import{j as t,M as F,r as v,B as N,J as L,w as k}from"./index-BIjT-aNh.js";import{L as U}from"./LoadErrorState-Bkxts8ln.js";import{A as W,a as B,b as H,c as R,d as K,e as G,f as X,g as q,h as Q}from"./alert-dialog-CmeDGxnw.js";import{a as V,g as Y,T as Z}from"./badgeUtils-CN-uXx26.js";import{S as ee}from"./star-C67ZY9-m.js";import{u as te}from"./940cc454792cc5d6ba3e93b0b7aaeb23ed8ad6ff-CfU5QyRn.js";import{fetchWishes as se}from"./myAccountService-CSYRfJ8q.js";import{u as ae}from"./useMuseumStatus-BqE2wotn.js";import{A as le}from"./arrow-left-DvZnGT50.js";import{T as re}from"./trash-2-CfrWiq-B.js";import{S as ie}from"./search-x-BNs_DB6R.js";import"./download-DFkQk4FP.js";import"./firebaseAuth-BbFzaUYv.js";import"./index.esm-dObGBr4t.js";function ce({hotel:s,isLiked:x,onToggleLike:g,onClick:n,priceText:S}){const w=s.originalPrice?Math.round((s.originalPrice-s.price)/s.originalPrice*100):0;return t.jsxs("div",{onClick:()=>n?.(s.id,s),className:"bg-white rounded-xl border border-[#E9ECEF] shadow-[0_2px_4px_rgba(0,0,0,0.05)] overflow-hidden hover:shadow-md transition-all group cursor-pointer",children:[t.jsxs("div",{className:"relative aspect-[4/3]",children:[t.jsx("img",{src:s.images[0],alt:s.name,className:"w-full h-full object-cover",loading:"lazy",decoding:"async"}),s.isGuidebookPick&&t.jsx("div",{className:"absolute top-3 left-3 bg-blue-600 text-white text-xs px-2 py-1 rounded",children:"바캉스 Pick"}),w>0&&t.jsxs("div",{className:"absolute bottom-3 left-3 bg-red-500 text-white text-xs px-2 py-1 rounded font-semibold",children:[w,"% 할인"]})]}),t.jsxs("div",{className:"p-4",children:[t.jsxs("div",{className:"flex items-start justify-between mb-2",children:[t.jsxs("div",{className:"flex-1",children:[t.jsx("h3",{className:"font-semibold mb-1 line-clamp-1",children:s.name}),t.jsxs("div",{className:"flex items-center gap-1 text-xs text-gray-600 mb-1",children:[t.jsx(F,{className:"w-3 h-3"}),t.jsx("span",{children:s.location})]}),s.distance&&t.jsx("div",{className:"text-xs text-gray-500",children:s.distance})]}),t.jsxs("div",{className:"flex items-center gap-1 ml-2",children:[t.jsx(ee,{className:"w-4 h-4 fill-yellow-400 text-yellow-400"}),t.jsx("span",{className:"font-semibold",children:s.rating})]})]}),t.jsx("div",{className:"flex flex-wrap gap-1 mb-3",children:s.features.slice(0,3).map((D,h)=>t.jsx("span",{className:"text-xs px-2 py-0.5 bg-gray-100 text-gray-600 rounded",children:D},h))}),t.jsxs("div",{className:"flex items-end justify-between",children:[t.jsx("div",{children:t.jsxs("div",{className:"flex items-baseline gap-1",children:[t.jsx("span",{className:"text-xl font-bold text-blue-600",children:S||`₩${s.price.toLocaleString()}`}),t.jsx("span",{className:"text-xs text-gray-500",children:"/박"})]})}),t.jsxs("div",{className:"text-xs text-gray-500",children:[s.reviewCount.toLocaleString(),"개 후기"]})]})]})]})}function oe(s){const x=s.trim();if(!x)return"";const g=x.match(/^([\d,.\s]+)([^\d,.\s]+)$/);return g?`${g[2]}${g[1].trim()}`:x}function E(s){const x=s.pricing||s.productData?.pricing||s.hotelData?.pricing,g=x?.lowest||x?.ratePerNight?.lowest;if(g)return oe(String(g))||void 0}function de(s,x){const g=s.type||"";if(g.includes("museum")){const n=x(s);return{statusLabel:n.label||void 0,statusColor:n.color||void 0}}return g==="hotel"?{statusLabel:s.zone||s.district||s.productData?.zone||s.productData?.district||s.hotelData?.zone||s.hotelData?.district||void 0,hotelPriceText:E(s)}:{}}const ne=[{id:"all",label:"All",active:!0},{id:"travel",label:"여행상품",active:!1},{id:"museum",label:"박물관",active:!1},{id:"schedule",label:"일정/가이드북",active:!1},{id:"hotel",label:"호텔",active:!1},{id:"restaurant",label:"레스토랑/카페",active:!1},{id:"other",label:"기타",active:!1}];function De({onPageChange:s,previousPage:x}){const g=ae(),[n,S]=v.useState("all"),[w,D]=v.useState("date-desc"),[h,A]=v.useState(!1),[u,b]=v.useState([]),[f,I]=v.useState([]),[$,T]=v.useState(!1),[O,z]=v.useState(0);v.useEffect(()=>{const e=async()=>{let i=[];T(!1);try{i=(await se(void 0,!0)).map(l=>({id:l.itemId||l.id,type:l.type||"city",title:l.title||"",titleEn:l.titleEn||"",image:l.thumbnail||l.image||"",location:l.cityName||l.location||"",city:l.cityName||l.city||"",cityCode:l.cityCode||"",category:l.category||"",pdfUrl:l.pdfUrl||"",savedAt:l.createdAt?.toDate?.()?.toISOString?.()||l.createdAt||new Date().toISOString(),...l})),console.log("☁️ [WishlistPage] Firestore에서",i.length,"개 로드")}catch(a){console.warn("⚠️ [WishlistPage] Firestore 로드 실패:",a),T(!0)}let c=[];try{c=JSON.parse(localStorage.getItem("lesvacances_favorites")||"[]")}catch{}const o=new Map;
1i.forEach(a=>o.set(`${a.id}_${a.type}`,a)),c.forEach(a=>{const l=`${a.id}_${a.type}`;if(!o.has(l))o.set(l,a);else{const _=o.get(l);o.set(l,{...a,..._})}});const j=Array.from(o.values()),y=j.map(a=>{if(a.type==="guidebook")return{...a,stars:a.stars||3,downloads:a.downloads||3400,location:a.location?.includes(" ")?a.location:`${a.location} ${a.city||""}`.trim()};if(a.type==="museum"){let l=a.image;return a.id==="uffizi-gallery"&&(l=te),{...a,rating:a.rating||3,downloads:a.downloads||3400,location:a.location||"이탈리아 피렌체",image:l}}return a}),d=50;let p=y;y.length>d&&(p=[...y].sort((a,l)=>new Date(l.savedAt).getTime()-new Date(a.savedAt).getTime()).slice(0,d),console.log(`🔧 [찜] ${y.length}개 → ${d}개로 제한`)),JSON.stringify(j)!==JSON.stringify(p)&&(localStorage.setItem("lesvacances_favorites",JSON.stringify(p)),console.log("🔧 가이드북 데이터 자동 보정 완료",p.filter(a=>a.type==="guidebook"))),I(p)};e();const r=()=>{e()};return window.addEventListener("favoritesUpdated",r),window.addEventListener("focus",e),()=>{window.removeEventListener("favoritesUpdated",r),window.removeEventListener("focus",e)}},[O]);const M=()=>n==="all"?f:n==="museum"?f.filter(e=>e.type==="museum"):n==="schedule"?f.filter(e=>e.type==="guidebook"||e.type==="schedule"):n==="travel"?f.filter(e=>e.type==="product"||e.type==="city"):n==="other"?f.filter(e=>!["museum","guidebook","schedule","product","city"].includes(e.type)):f.filter(e=>e.type===n),m=(()=>{const e=M();switch(w){case"date-desc":return[...e].sort((r,i)=>new Date(i.savedAt).getTime()-new Date(r.savedAt).getTime());case"date-asc":return[...e].sort((r,i)=>new Date(r.savedAt).getTime()-new Date(i.savedAt).getTime());case"city-asc":return[...e].sort((r,i)=>(r.location||"").localeCompare(i.location||"","ko-KR"));default:return e}})(),C=(e,r)=>{b(r?i=>[...i,e]:i=>i.filter(c=>c!==e))},P=()=>{u.length===m.length?b([]):b(m.map(e=>e.id))},J=()=>{if(u.length===0)return;const e=f.filter(r=>!u.includes(r.id));I(e),localStorage.setItem("lesvacances_favorites",JSON.stringify(e)),u.forEach(r=>{const i=f.find(c=>c.id===r);if(i){if(i.type==="product"){const o=JSON.parse(localStorage.getItem("travelProductLikes")||"[]").filter(j=>j!==Number(r));localStorage.setItem("travelProductLikes",JSON.stringify(o))}if(i.type==="city"){const c=JSON.parse(localStorage.getItem("likedCities")||"[]"),o=c.indexOf(r);o>-1&&(c.splice(o,1),localStorage.setItem("likedCities",JSON.stringify(c)))}else if(i.type==="museum"){const c=JSON.parse(localStorage.getItem("likedMuseums")||"[]"),o=c.indexOf(r);o>-1&&(c.splice(o,1),localStorage.setItem("likedMuseums",JSON.stringify(c)))}}}),window.dispatchEvent(new Event("favoritesUpdated")),b([]),A(!1),k.success(`${u.length}개의 아이템이 삭제되었습니다.`)};return t.jsxs("div",{className:"min-h-screen page-bg",children:[t.jsx("div",{className:"bg-white sticky top-0 z-50 border-b border-gray-200",children:t.jsxs("div",{className:"flex items-center justify-between p-4",children:[t.jsxs("div",{className:"flex items-center",children:[t.jsx(N,{variant:"ghost",size:"sm",onClick:()=>s(x||"account"),className:"mr-2 p-1",children:t.jsx(le,{className:"w-5 h-5"})}),t.jsx("h1",{className:"text-xl flex-1 text-center",children:"찜 리스트"})]}),t.jsx(N,{variant:"ghost",size:"sm",className:"text-gray-500 text-sm p-0 hover:text-gray-700 transition-colors",onClick:()=>{A(!h),b([])},children:h?"완료":"편집"})]})}),t.jsxs("div",{className:"py-6",children:[t.jsxs("div",{className:"flex flex-col space-y-4 mb-4 overflow-visible px-0",children:[t.jsx("div",{className:"overflow-x-auto scrollbar-hide touch-scroll cursor-grab active:cursor-grabbing w-full",children:t.jsx("div",{className:"flex space-x-3 px-4 pb-2 min-w-max",children:ne.map(e=>t.jsx(N,{variant:n===e.id?"default":"outline",size:"sm",onClick:()=>S(e.id),className:`rounded-full px-3 py-2 text-sm whitespace-nowrap flex-shrink-0 scroll-snap-start min-w-fit transition-all duration-200 ${n===e.id?"bg-blue-500 text-white border-blue-500":"bg-white text-gray-600 border-gray-300 hover:border-blue-300"}`,children:e.label},e.id))})}),t.jsx("div",{className:"px-4 py-2 border border-gray-200 rounded-lg bg-gray-50 mb-4",children:t.jsxs("div",{className:"flex items-center justify-between",children:[t.jsxs("span",{className:"text-sm text-gray-600",children:["총 ",m.length,"개의 찜"]}),t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx("span",{className:"text-sm text-gray-500",children:"정렬:"}),t.jsxs("select",{value:w,onChange:e=>D(e.target.value),className:"text-[16px] border border-gray-300 rounded px-2 py-1 bg-white",children:[t.jsx("option",{value:"date-desc",children:"최신순"}),t.jsx("option",{value:"date-asc",children:"오래된순"}),t.jsx("option",{value:"city-asc",children:"도시순"})]})]})]})})]}),h&&t.jsxs("div",{className:"flex justify-between items-center px-4 py-3 bg-blue-50 border-t border-blue-100",children:[t.jsxs("div",{className:"flex items-center space-x-3",children:[t.jsx(L,{checked:u.length===m.length&&m.length>0,onCheckedChange:P,className:"data-[state=checked]:bg-blue-500 data-[state=checked]:border-blue-500"}),t.jsxs("span",{className:"text-sm text-gray-700",children:["전체 선택 (",u.length,"/",m.length,")"]})]}),t.jsxs(W,{children:[t.jsx(B,{asChild:!0,children:t.jsxs(N,{variant:"destructive",size:"sm",disabled:u.length===0,className:"text-sm",children:[t.jsx(re,{className:"w-4 h-4 mr-1"}),"삭제 (",u.length,")"]})}
1),t.jsxs(H,{children:[t.jsxs(R,{children:[t.jsx(K,{children:"선택한 아이템을 삭제하시겠습니까?"}),t.jsxs(G,{children:["선택한 ",u.length,"개의 아이템이 찜 리스트에서 영구적으로 삭제됩니다. 이 작업은 되돌릴 수 없습니다."]})]}),t.jsxs(X,{children:[t.jsx(q,{children:"취소"}),t.jsx(Q,{onClick:J,className:"bg-red-500 hover:bg-red-600",children:"삭제"})]})]})]})]}),$?t.jsx(U,{title:"찜 목록을 불러오지 못했습니다",onRetry:()=>z(e=>e+1)}):m.length===0?t.jsx("div",{className:"flex flex-col items-center justify-center py-16 px-4",children:t.jsxs("div",{className:"text-center max-w-md",children:[t.jsx("div",{className:"mb-4",children:t.jsx(ie,{className:"w-16 h-16 mx-auto text-gray-300"})}),t.jsx("h3",{className:"text-lg mb-2 text-gray-700",children:"검색 결과가 없습니다"}),t.jsxs("p",{className:"text-sm text-gray-500 mb-6",children:["선택하신 필터에 해당하는 찜이 없습니다.",t.jsx("br",{}),"다른 필터를 선택해 보세요."]}),t.jsx(N,{onClick:()=>S("all"),className:"bg-blue-500 hover:bg-blue-600 text-white",children:"전체 보기"})]})}):t.jsx("div",{className:"grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 xl:grid-cols-7 gap-3 px-4",children:m.map((e,r)=>{const i=V(e.type),c=Y(e.type),o=c.match(/bg-(\w+)-\d+/);o&&o[1];const j=()=>
1{if(h)C(e.id,!u.includes(e.id));else if(e.type==="pdf"){const d=e.pdfUrl;d?s("pdf-viewer",void 0,{pdfUrl:d,title:e.title||"PDF",pdfMeta:{docId:e.id,title:e.title||"PDF",thumbnail:e.image||"",cityName:e.location||e.city||"",category:e.category||"PDF"}}):k.info("PDF를 열 수 없습니다.")}else if(e.type==="museum")s("museum-detail",e.id);else if(e.type==="city")s("city-detail",e.id);else if(e.type==="guidebook"){const d=e.cityId||e.id.replace("guide_","");console.log("📖 가이드북 클릭:",{itemId:e.id,cityId:d,fullItem:e}),s("my-guidebook-detail",e.id)}else e.type==="schedule"?k.info("일정 상세 페이지는 준비 중입니다."):e.type==="product"?s("travel-product-detail",void 0,{productData:e.productData||e,backPage:"wishlist"}):e.type==="hotel"&&s("hotel-detail",e.id,{item:e.hotelData||{name:e.title,images:e.image?[e.image]:[],rating:e.rating||5,location:e.location||"",reviewCount:e.reviews||e.downloads||0},hotelName:e.title,image:e.image})};if(e.type==="hotel"&&e.hotelData){const d=e.hotelData;return t.jsxs("div",{className:"relative",children:[h&&t.jsx("div",{className:"absolute top-2 left-2 z-20",children:t.jsx(L,{checked:u.includes(e.id),onCheckedChange:p=>C(e.id,p),className:"data-[state=checked]:bg-blue-500 data-[state=checked]:border-blue-500 bg-white"})}),t.jsx(ce,{hotel:d,isLiked:!0,priceText:E(e),onToggleLike:p=>{const a=f.filter(l=>l.id!==p);I(a),localStorage.setItem("lesvacances_favorites",JSON.stringify(a)),window.dispatchEvent(new Event("favoritesUpdated")),k.success("찜이 해제되었습니다.")},onClick:()=>{h||s("hotel-detail",e.id,{item:d,hotelName:d.name,image:d.images[0]})}})]},`wishlist-hotel-${e.id}-${r}`)}const y=de(e,g);return t.jsx(Z,{image:e.image,title:e.title,badge:void 0,rating:e.rating,stars:e.stars,location:e.type==="hotel"?void 0:e.location||e.subtitle||"",typeBadge:i,typeBadgeStyle:c,statusLabel:y.statusLabel,statusColor:y.statusColor,priceText:y.hotelPriceText,onClick:j,isEditMode:h,isSelected:u.includes(e.id),onCheckboxChange:d=>C(e.id,d),fullWidth:!0},`wishlist-${e.type}-${e.id}-${r}`)})})]})]})}export{De as WishlistPage};

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.