PageSourceSearch

https://slantapp.ai/assets/MeninasTourPage-CvmzC4Qh.js

js slantapp.ai collected 2026-10-05 15:06:14 UTC 13,072 bytes, 8 lines download raw bytes

1import{f as V,u as H,r as l,ck as W,ch as Z,cl as q,cm as M,cn as D,co as J,j as e,n as R,B as E,S as U,ax as X,Y as I,O as Y,X as K,cp as Q}from"./index-tc5-nNLC.js";import{A as ee}from"./arrow-left-kYemJdx8.js";const h={porta:"#F97316",baluarte:"#3B82F6",cruceiro:"#8B5CF6",tafona:"#EC4899"},F={porta:"Porta de Canido",baluarte:"Baluarte / Parque Antón Varela",cruceiro:"Cruceiro de Canido",tafona:"Praza da Tafona"},m=J,te=D,O="meninas-tour-2026-visited";function L(o,f){const p=f?"#475569":h[o.zone],i=f?"#94A3B8":"#ffffff",r=o.large?34:28,g=o.number>=10?10:12,k=Math.round(r/2+4),a=f?`<svg xmlns="http://www.w3.org/2000/svg" width="${r}" height="${r}">
2        <circle cx="${r/2}" cy="${r/2}" r="${r/2-2}" fill="${p}" stroke="${i}" stroke-width="2.5"/>
3        <line x1="${r*.3}" y1="${r*.55}" x2="${r*.45}" y2="${r*.7}" stroke="white" stroke-width="2" stroke-linecap="round"/>
4        <line x1="${r*.45}" y1="${r*.7}" x2="${r*.72}" y2="${r*.35}" stroke="white" stroke-width="2" stroke-linecap="round"/>
5      </svg>`:`<svg xmlns="http://www.w3.org/2000/svg" width="${r}" height="${r}">
6        <circle cx="${r/2}" cy="${r/2}" r="${r/2-2}" fill="${p}" stroke="${i}" stroke-width="2.5"/>
7        <text x="${r/2}" y="${k}" text-anchor="middle" font-family="Arial,sans-serif" font-size="${g}" font-weight="bold" fill="white">${o.number}</text>
8      </svg>`;return{url:`data:image/svg+xml;charset=UTF-8,${encodeURIComponent(a)}`,scaledSize:new window.google.maps.Size(r,r),anchor:new window.google.maps.Point(r/2,r/2)}}function ne(){var z;const{isAuthenticated:o}=V(),[,f]=H(),p=l.useRef(null),i=l.useRef(null),r=l.useRef(new Map),[g,k]=l.useState(!!((z=window.google)!=null&&z.maps)),[a,w]=l.useState(null),[b,j]=l.useState(!1),[$,v]=l.useState(null),y=l.useRef(null),[c,C]=l.useState(()=>{try{const t=localStorage.getItem(O);return t?new Set(JSON.parse(t)):new Set}catch{return new Set}});l.useEffect(()=>{var s;if((s=window.google)!=null&&s.maps||window.googleMapsLoaded){k(!0);return}const t=()=>k(!0);return window.addEventListener("googleMapsReady",t),()=>window.removeEventListener("googleMapsReady",t)},[]),l.useEffect(()=>{o&&fetch(`/api/chains/${W}/location-progress`,{credentials:"include"}).then(t=>t.ok?t.json():null).then(t=>{Array.isArray(t==null?void 0:t.visitedStops)&&C(new Set(t.visitedStops))}).catch(()=>{})},[o]),l.useEffect(()=>()=>{y.current!==null&&navigator.geolocation.clearWatch(y.current)},[]);const S=l.useCallback(()=>{if(!navigator.geolocation){v("Location tracking is not supported by this browser.");return}v(null),Z();const t=q();y.current=navigator.geolocation.watchPosition(async({coords:s})=>{var n;try{const u=await fetch("/api/qr-registry/track-location",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({deviceFingerprint:t,latitude:s.latitude,longitude:s.longitude,accuracy:s.accuracy})});if(!u.ok)throw new Error("Could not record your location.");const A=((await u.json()).geofences??[]).map(x=>x.id).filter(x=>typeof x=="string"&&x.startsWith(M)).map(x=>Number(x.slice(M.length))).filter(Number.isFinite);A.length&&C(x=>new Set([...Array.from(x),...A])),j(!0)}catch(u){v(((n=u==null?void 0:u.body)==null?void 0:n.error)??"Could not record your location.")}},s=>{j(!1),v(s.message||"Location permission was not granted.")},{enableHighAccuracy:!0,maximumAge:1e4,timeout:2e4}),j(!0)},[]);l.useEffect(()=>{if(b||y.current!==null)return;(async()=>{var s;if(Q()){try{const n=await((s=navigator.permissions)==null?void 0:s.query({name:"geolocation"}));if((n==null?void 0:n.state)==="denied"){v("Location permission is disabled in this browser.");return}}catch{}S()}})()},[S,b]);const T=l.useCallback((t,s)=>{const n=r.current.get(t.number);n&&(n.setIcon(L(t,s)),n.setZIndex(s?1:t.large?10:5))},[]);l.useEffect(()=>{if(!g||!p.current||i.current)return;const t=new window.google.maps.Map(p.current,{center:te,zoom:15,mapTypeControl:!1,streetViewControl:!1,fullscreenControl:!1,zoomControlOptions:{position:window.google.maps.ControlPosition.RIGHT_CENTER},styles:[{featureType:"poi",elementType:"labels",stylers:[{visibility:"off"}]},{featureType:"transit",elementType:"labels",stylers:[{visibility:"off"}]}]});i.current=t,m.forEach(s=>{const n=c.has(s.number),u=new window.google.maps.Marker({position:{lat:s.lat,lng:s.lng},map:t,title:`${s.number}. ${s.artist}`,icon:L(s,n),zIndex:n?1:s.large?10:5});u.addListener("click",()=>{w(s),t.panTo({lat:s.lat,lng:s.lng})}),r.current.set(s.number,u)})},[g]),l.useEffect(()=>{i.current&&m.forEach(t=>T(t,c.has(t.number)))},[c,T]);const P=t=>{C(s=>{const n=new Set(s);n.has(t)?n.delete(t):n.add(t);try{localStorage.setItem(O,JSON.stringify(Array.from(n)))}catch{}return n})},_=t=>{const s=`https://www.google.com/maps/dir/?api=1&destination=${t.lat},${t.lng}&travelmode=walking`;window.open(s,"_blank","noopener,noreferrer")},d=m.find(t=>!c.has(t.number)),B=Math.round(c.size/m.length*100),N=c.size===m.length,G=()=>
8{const t="/chain-plan/campaign/jori-meninas-campaign-2026";try{const s=sessionStorage.getItem("ferrol-chain-return-url");if(s!=null&&s.startsWith("/chain-plan/")){f(s);return}}catch{}f(t)};return e.jsxs("div",{className:"fixed inset-0 bg-slate-950 flex flex-col overflow-hidden","data-testid":"meninas-tour-page",children:[e.jsxs("div",{className:"flex items-center justify-between px-4 py-3 bg-slate-900/95 backdrop-blur-sm border-b border-slate-800 z-10 flex-shrink-0",children:[e.jsxs("button",{onClick:G,className:"flex items-center gap-1.5 text-slate-400 hover:text-white transition-colors","data-testid":"button-tour-back",children:[e.jsx(ee,{className:"w-4 h-4"}),e.jsx("span",{className:"text-sm",children:"Back"})]}),e.jsxs("div",{className:"text-center",children:[e.jsx("p",{className:"text-white font-bold text-sm leading-none",children:"Meninas de Canido"}),e.jsx("p",{className:"text-slate-400 text-[11px] mt-0.5",children:"Art Trail · Canido, Ferrol"})]}),e.jsxs("div",{className:`flex items-center gap-1.5 rounded-full px-2.5 py-1 transition-colors ${N?"bg-emerald-900/60":"bg-slate-800"}`,children:[e.jsx(R,{className:`w-3 h-3 ${N?"text-emerald-400":"text-slate-400"}`}),e.jsxs("span",{className:`text-xs font-bold ${N?"text-emerald-300":"text-white"}`,"data-testid":"text-progress-count",children:[c.size,"/",m.length]})]})]}),e.jsxs("div",{className:"flex items-center justify-between gap-3 px-4 py-2 bg-slate-900 border-b border-slate-800",children:[e.jsx("p",{className:"text-[10px] text-slate-400 leading-tight",children:b?"Live location is on. Visits are verified only while this tour is open.":"Registered members can opt in to foreground GPS verification."}),e.jsx(E,{size:"sm",onClick:b?void 0:S,disabled:b,className:b?"bg-emerald-700 text-white":"bg-blue-600 hover:bg-blue-500 text-white","data-testid":"button-enable-tour-tracking",children:b?"Tracking on":"Enable tracking"})]}),$&&e.jsx("div",{className:"px-4 py-2 text-xs text-amber-200 bg-amber-950/70",role:"alert",children:$}),e.jsxs("div",{className:"flex-1 relative",style:{minHeight:0},children:[e.jsx("div",{ref:p,className:"w-full h-full","data-testid":"tour-map-container"}),!g&&e.jsx("div",{className:"absolute inset-0 flex items-center justify-center bg-slate-900",children:e.jsxs("div",{className:"text-center",children:[e.jsx("div",{className:"animate-spin rounded-full h-8 w-8 border-2 border-amber-500 border-t-transparent mx-auto mb-3"}),e.jsx("p",{className:"text-slate-400 text-sm",children:"Loading map…"})]})}),e.jsxs("div",{className:"absolute top-3 left-3 bg-slate-900/90 backdrop-blur-sm rounded-xl p-3 border border-slate-700/50 space-y-1.5",children:[e.jsx("p",{className:"text-slate-500 text-[9px] font-bold uppercase tracking-widest mb-1",children:"Zones"}),Object.entries(h).map(([t,s])=>e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"w-3 h-3 rounded-full flex-shrink-0",style:{backgroundColor:s}}),e.jsx("span",{className:"text-slate-300 text-[10px] leading-tight whitespace-nowrap",children:F[t].split(" /")[0].split(" (")[0]})]},t)),e.jsxs("div",{className:"border-t border-slate-700/50 pt-1.5 mt-0.5 flex items-center gap-2",children:[e.jsx("div",{className:"w-3 h-3 rounded-full bg-slate-600 flex-shrink-0"}),e.jsx("span",{className:"text-slate-500 text-[10px]",children:"Visited"})]})]}),g&&!a&&e.jsx("div",{className:"absolute bottom-4 left-1/2 -translate-x-1/2 z-10",children:N?e.jsxs("div",{className:"flex items-center gap-2 bg-emerald-900/90 backdrop-blur-sm text-emerald-300 font-bold px-5 py-2.5 rounded-full border border-emerald-700/50 shadow-lg text-sm",children:[e.jsx(U,{className:"w-4 h-4 text-emerald-400"}),"All 21 Meninas Found!"]}):c.size===0?e.jsxs("button",{onClick:()=>{var t;d&&(w(d),(t=i.current)==null||t.panTo({lat:d.lat,lng:d.lng}))},className:"flex items-center gap-2 bg-amber-500 hover:bg-amber-400 text-slate-950 font-bold px-5 py-2.5 rounded-full shadow-lg transition-colors text-sm","data-testid":"button-start-tour",children:[e.jsx(X,{className:"w-4 h-4"}),"Start the Tour"]}):d?e.jsxs("button",{onClick:()=>{var t;w(d),(t=i.current)==null||t.panTo({lat:d.lat,lng:d.lng})},className:"flex items-center gap-2 bg-slate-800/95 hover:bg-slate-700 text-white backdrop-blur-sm px-4 py-2 rounded-full border border-slate-600 shadow-lg transition-colors text-sm","data-testid":"button-next-stop",children:[e.jsx(I,{className:"w-3.5 h-3.5 text-blue-400"}),"Next: #",d.number," ",d.artist]}):null}),e.jsx("div",{className:"absolute bottom-0 left-0 right-0 h-1 bg-slate-800/80",children:e.jsx("div",{className:"h-full transition-all duration-500",style:{width:`${B}%`,background:N?"linear-gradient(to right, #10b981, #34d399)":"linear-gradient(to right, #f59e0b, #3b82f6)"}})})]}),!a&&g&&e.jsx("div",{className:"bg-slate-900/95 backdrop-blur-sm border-t border-slate-800 px-4 py-2.5 flex-shrink-0 z-10",children:e.jsx("p",{className:"text-slate-500 text-xs text-center",children:"Tap a numbered marker to see the artist and get walking directions"})}),a&&e.jsxs("div",{className:"bg-slate-900 border-t border-slate-700 px-4 pt-4 pb-6 z-20 flex-shrink-0","data-testid":"tour-stop-sheet",children:[e.jsxs("div",{className:"flex items-start justify-between mb-3",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:"w-10 h-10 rounded-full flex items-center justify-center flex-shrink-0 font-black text-white text-sm shadow-md",style:{backgroundColor:h[a.zone]},"data-testid":"text-stop-number",children:a.number}),e.jsxs("div",{children:[e.jsx("h2",{className:"text-white font-bold text-base leading-tight","data-testid":"text-stop-artist",children:a.artist}),a.note&&e.jsx("p",{className:"text-amber-400 text-xs mt-0.5",children:a.note}),e.jsx(Y,{variant:"outline",className:"mt-1 text-[10px] font-medium",style:{color:h[a.zone],borderColor:h[a.zone]+"55",backgroundColor:h[a.zone]+"15"},"data-testid":"text-stop-zone",children:F[a.zone]})]})]}),e.jsx("button",{onClick:()=>w(null),className:"text-slate-500 hover:text-slate-300 transition-colors mt-0.5 flex-shrink-0","data-testid":"button-close-sheet",children:e.jsx(K,{className:"w-5 h-5"})})]}),e.jsxs("div",{className:"flex items-center gap-2 mb-3",children:[e.jsx("div",{className:"h-px flex-1 opacity-20",style:{backgroundColor:h[a.zone]}}),e.jsx("span",{className:"text-slate-500 text-[10px] font-medium uppercase tracking-wider",children:a.large?"★ Large Format Menina":"Small / Medium Format"}),e.jsx("div",{className:"h-px flex-1 opacity-20",style:{backgroundColor:h[a.zone]}})]}),e.jsxs("div",{className:"flex gap-3",children:[e.jsxs(E,{className:"flex-1 bg-blue-600 hover:bg-blue-500 text-white gap-2 font-semibold",onClick:()=>_(a),"data-testid":"button-walk-here",children:[e.jsx(I,{className:"w-4 h-4"}),"Walk Here"]}),e.jsxs(E,{variant:"outline",className:`flex-1 gap-2 font-semibold transition-colors ${c.has(a.number)?"bg-emerald-900/50 border-emerald-700 text-emerald-400 hover:bg-emerald-900/80":"border-slate-600 text-slate-300 hover:bg-slate-800"}`,onClick:()=>!o&&P(a.number),disabled:o,"data-testid":"button-mark-visited",children:[e.jsx(R,{className:"w-4 h-4"}),c.has(a.number)?"Verified ✓":o?"Verify by location":"Mark Visited"]})]}),e.jsxs("div",{className:"flex items-center justify-between mt-3 pt-3 border-t border-slate-800",children:[e.jsxs("button",{onClick:()=>{var s;const t=m[a.number-2];t&&(w(t),(s=i.current)==null||s.panTo({lat:t.lat,lng:t.lng}))},disabled:a.number===1,className:"text-slate-400 hover:text-white disabled:opacity-30 disabled:cursor-not-allowed text-xs transition-colors","data-testid":"button-prev-stop",children:["← #",a.number-1]}),e.jsxs("span",{className:"text-slate-600 text-xs",children:["Stop ",a.number," of ",m.length]}),e.jsxs("button",{onClick:()=>{var s;const t=m[a.number];t&&(w(t),(s=i.current)==null||s.panTo({lat:t.lat,lng:t.lng}))},disabled:a.number===m.length,className:"text-slate-400 hover:text-white disabled:opacity-30 disabled:cursor-not-allowed text-xs transition-colors","data-testid":"button-next-stop-nav",children:["#",a.number+1," →"]})]})]})]})}export{ne 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.