carrier info fix, right widget update, live tracking device upd, bug fixes
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				release-tag / release-image (push) Successful in 55s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	release-tag / release-image (push) Successful in 55s
				
			This commit is contained in:
		| @@ -112,6 +112,24 @@ body { | |||||||
|   margin-bottom: 15px; |   margin-bottom: 15px; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .back-button { | ||||||
|  |   border: none; | ||||||
|  |   font-size: 22px; | ||||||
|  |   font-weight: 600; | ||||||
|  |   text-align: left; | ||||||
|  |   padding: 15px; | ||||||
|  |   color: #fff; | ||||||
|  |   background: rgb(187, 179, 170); | ||||||
|  |   background: linear-gradient( | ||||||
|  |     180deg, | ||||||
|  |     rgba(187, 179, 170, 1) 0%, | ||||||
|  |     rgba(159, 148, 135, 1) 100% | ||||||
|  |   ); | ||||||
|  |   display: flex; | ||||||
|  |   align-items: center; | ||||||
|  |   gap: 10px; | ||||||
|  | } | ||||||
|  |  | ||||||
| .stopdescription { | .stopdescription { | ||||||
|   font-size: 16px; |   font-size: 16px; | ||||||
|   font-weight: 400; |   font-weight: 400; | ||||||
| @@ -687,6 +705,7 @@ body { | |||||||
| } | } | ||||||
|  |  | ||||||
| .dropdown-name { | .dropdown-name { | ||||||
|  |   position: relative; | ||||||
|   font-size: 18px; |   font-size: 18px; | ||||||
|   font-weight: 600; |   font-weight: 600; | ||||||
|   color: #fff; |   color: #fff; | ||||||
| @@ -695,7 +714,6 @@ body { | |||||||
|   display: flex; |   display: flex; | ||||||
|   flex-direction: column; |   flex-direction: column; | ||||||
|   align-items: center; |   align-items: center; | ||||||
|   text-align: center; |  | ||||||
|   width: 100%; |   width: 100%; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -1231,3 +1249,25 @@ li.checked { | |||||||
|   flex: 0 0 calc((100% - 24px) / 3); |   flex: 0 0 calc((100% - 24px) / 3); | ||||||
|   box-sizing: border-box; |   box-sizing: border-box; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .carrier-container { | ||||||
|  |   display: flex; | ||||||
|  |   align-items: center; | ||||||
|  |   justify-content: center; | ||||||
|  |   flex-direction: column; | ||||||
|  |   gap: 15px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .carrier-img { | ||||||
|  |   width: 100%; | ||||||
|  |   padding: 0; | ||||||
|  |   margin: 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .carrier-slogan { | ||||||
|  |   font-size: 18px; | ||||||
|  |   color: #fff; | ||||||
|  |   opacity: 70%; | ||||||
|  |   text-align: center; | ||||||
|  |   font-style: italic; | ||||||
|  | } | ||||||
|   | |||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -74,6 +74,8 @@ export default { | |||||||
|       manualTramDirection: null, |       manualTramDirection: null, | ||||||
|       manualDirectionUntil: 0, |       manualDirectionUntil: 0, | ||||||
|       inactivityTimer: null, |       inactivityTimer: null, | ||||||
|  |       isFollowingTram: false, | ||||||
|  |       followTramTimer: null, | ||||||
|       chooseTramDirection(canvasPt) { |       chooseTramDirection(canvasPt) { | ||||||
|         // canvasPt: [x, y] in PIXI coords |         // canvasPt: [x, y] in PIXI coords | ||||||
|         let bestDir = "right"; |         let bestDir = "right"; | ||||||
| @@ -141,6 +143,12 @@ export default { | |||||||
|     resetInactivity() { |     resetInactivity() { | ||||||
|       this.lastActivityTime = Date.now(); |       this.lastActivityTime = Date.now(); | ||||||
|       if (this.videoOverlayVisible) this.hideVideoOverlay(); |       if (this.videoOverlayVisible) this.hideVideoOverlay(); | ||||||
|  |       clearTimeout(this.inactivityTimer); | ||||||
|  |       // stop following on any user activity | ||||||
|  |       this.isFollowingTram = false; | ||||||
|  |       this.stopFollowTram(); | ||||||
|  |       // restart inactivity timer on any user activity | ||||||
|  |       this.resetInactivityTimer(); | ||||||
|     }, |     }, | ||||||
|     startInactivityCheck() { |     startInactivityCheck() { | ||||||
|       if (this.inactivityInterval) return; |       if (this.inactivityInterval) return; | ||||||
| @@ -325,20 +333,17 @@ export default { | |||||||
|       const minLat = Math.min(...lats); |       const minLat = Math.min(...lats); | ||||||
|       const maxLat = Math.max(...lats); |       const maxLat = Math.max(...lats); | ||||||
|       const minLng = Math.min(...lngs); |       const minLng = Math.min(...lngs); | ||||||
|       const maxLng = Math.max(...lngs); |  | ||||||
|  |  | ||||||
|       const canvas = this.pixiApp.canvas; |  | ||||||
|       const width = canvas.width; |  | ||||||
|       const height = canvas.height; |  | ||||||
|       const padding = 40; |       const padding = 40; | ||||||
|  |  | ||||||
|       const scaleX = (width - padding * 2) / (maxLng - minLng || 1); |       const scale = 35000; | ||||||
|       const scaleY = (height - padding * 2) / (maxLat - minLat || 1); |       const midLat = (minLat + maxLat) / 2; | ||||||
|       let scale = 30000; |       const latFactor = Math.cos((midLat * Math.PI) / 180); | ||||||
|       console.log(scaleX, scaleY, scale); |       console.log( | ||||||
|  |         `Using fixed scale ${scale} and latFactor ${latFactor.toFixed(4)}` | ||||||
|  |       ); | ||||||
|  |  | ||||||
|       const toPoint = ([lat, lng]) => { |       const toPoint = ([lat, lng]) => { | ||||||
|         const x = (lng - minLng) * scale + padding; |         const x = (lng - minLng) * scale * latFactor + padding; | ||||||
|         const y = (maxLat - lat) * scale + padding; |         const y = (maxLat - lat) * scale + padding; | ||||||
|         return { x, y }; |         return { x, y }; | ||||||
|       }; |       }; | ||||||
| @@ -1079,29 +1084,39 @@ export default { | |||||||
|     }, |     }, | ||||||
|     // reset the inactivity timeout |     // reset the inactivity timeout | ||||||
|     resetInactivityTimer() { |     resetInactivityTimer() { | ||||||
|  |       console.log("[inactivity] scheduling follow in 15s"); | ||||||
|       clearTimeout(this.inactivityTimer); |       clearTimeout(this.inactivityTimer); | ||||||
|       this.inactivityTimer = setTimeout(() => { |       this.inactivityTimer = setTimeout(() => { | ||||||
|  |         this.isFollowingTram = true; | ||||||
|  |         this.startFollowTram(); | ||||||
|  |       }, 15000); | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     startFollowTram() { | ||||||
|  |       console.log("[follow] startFollowTram() triggered"); | ||||||
|  |       if (this.followTramTimer) return; | ||||||
|  |       this.followTramTimer = setInterval(() => { | ||||||
|         if (this.tramContainer) { |         if (this.tramContainer) { | ||||||
|           // compute tram position in viewport world coordinates |           const local = new PIXI.Point( | ||||||
|           const localPoint = new PIXI.Point( |  | ||||||
|             this.tramContainer.x, |             this.tramContainer.x, | ||||||
|             this.tramContainer.y |             this.tramContainer.y | ||||||
|           ); |           ); | ||||||
|           const worldCenter = this.viewport.toLocal( |           const worldCenter = this.viewport.toLocal(local, this.routeGroup); | ||||||
|             localPoint, |  | ||||||
|             this.routeGroup |  | ||||||
|           ); |  | ||||||
|           // smooth pan and zoom to tram |  | ||||||
|           this.viewport.animate({ |           this.viewport.animate({ | ||||||
|             time: 600, |             time: 600, | ||||||
|             position: { x: worldCenter.x, y: worldCenter.y }, |             position: { x: worldCenter.x, y: worldCenter.y }, | ||||||
|             scale: 1, |             scale: 1, | ||||||
|             easing: "easeInOutSine", |             easing: "easeInOutSine", | ||||||
|           }); |           }); | ||||||
|           // schedule next recenter |  | ||||||
|           this.resetInactivityTimer(); |  | ||||||
|         } |         } | ||||||
|       }, 15000); |       }, 500); | ||||||
|  |     }, | ||||||
|  |     stopFollowTram() { | ||||||
|  |       console.log("[follow] stopFollowTram() triggered"); | ||||||
|  |       if (this.followTramTimer) { | ||||||
|  |         clearInterval(this.followTramTimer); | ||||||
|  |         this.followTramTimer = null; | ||||||
|  |       } | ||||||
|     }, |     }, | ||||||
|  |  | ||||||
|     // start watching for user interactions |     // start watching for user interactions | ||||||
| @@ -1125,6 +1140,10 @@ export default { | |||||||
|       clearInterval(this.inactivityInterval); |       clearInterval(this.inactivityInterval); | ||||||
|       this.inactivityInterval = null; |       this.inactivityInterval = null; | ||||||
|     } |     } | ||||||
|  |     if (this.followTramTimer) { | ||||||
|  |       clearInterval(this.followTramTimer); | ||||||
|  |       this.followTramTimer = null; | ||||||
|  |     } | ||||||
|     ["mousemove", "mousedown", "keydown", "touchstart", "scroll"].forEach( |     ["mousemove", "mousedown", "keydown", "touchstart", "scroll"].forEach( | ||||||
|       (evt) => window.removeEventListener(evt, this.resetInactivity) |       (evt) => window.removeEventListener(evt, this.resetInactivity) | ||||||
|     ); |     ); | ||||||
|   | |||||||
| @@ -43,6 +43,26 @@ | |||||||
|             class="watermark watermark-rd" |             class="watermark watermark-rd" | ||||||
|           /> |           /> | ||||||
|         </div> |         </div> | ||||||
|  |         <button | ||||||
|  |           v-if="showBackButton" | ||||||
|  |           class="back-button" | ||||||
|  |           @click="returnToNearestSight" | ||||||
|  |         > | ||||||
|  |           <svg | ||||||
|  |             xmlns="http://www.w3.org/2000/svg" | ||||||
|  |             width="12" | ||||||
|  |             height="21" | ||||||
|  |             fill="none" | ||||||
|  |             viewBox="0 0 12 21" | ||||||
|  |           > | ||||||
|  |             <path | ||||||
|  |               fill="#fff" | ||||||
|  |               d="M3.53 10.574c.188.135.316.203.414.3 2.486 2.495 4.966 4.992 7.451 7.486.445.447.623.96.44 1.574a1.485 1.485 0 0 1-2.383.716c-.09-.076-.171-.16-.254-.244L.658 11.82c-.878-.885-.877-1.673.003-2.56C3.539 6.364 6.414 3.463 9.307.58c.252-.25.606-.46.948-.542.646-.154 1.26.184 1.563.75.307.566.22 1.274-.238 1.764-.352.378-.725.736-1.09 1.101-2.195 2.204-4.389 4.407-6.585 6.609-.082.083-.179.15-.374.312Z" | ||||||
|  |             /> | ||||||
|  |           </svg> | ||||||
|  |  | ||||||
|  |           {{ t("back") }} | ||||||
|  |         </button> | ||||||
|         <span class="stopname">{{ stopName }}</span> |         <span class="stopname">{{ stopName }}</span> | ||||||
|         <span class="stopdescription">{{ selectedArticleBody }}</span> |         <span class="stopdescription">{{ selectedArticleBody }}</span> | ||||||
|         <div class="stoparticles"> |         <div class="stoparticles"> | ||||||
| @@ -261,6 +281,11 @@ export default { | |||||||
|       defaultImageUrl: |       defaultImageUrl: | ||||||
|         "https://lh3.googleusercontent.com/gps-cs-s/AB5caB8lUwofb2NIg6n0-cEl8nIWsySAUc52KNj4XezuOdo-aeqTgQlD1kTVa5MaynL2Yg4ByoTYTKNTR7K59f7kjzU9yzpudstjRiT2F6M_ilxFYFpcvMZz6OwlRFF2MrsCPSwUa7vqew=s680-w680-h510", |         "https://lh3.googleusercontent.com/gps-cs-s/AB5caB8lUwofb2NIg6n0-cEl8nIWsySAUc52KNj4XezuOdo-aeqTgQlD1kTVa5MaynL2Yg4ByoTYTKNTR7K59f7kjzU9yzpudstjRiT2F6M_ilxFYFpcvMZz6OwlRFF2MrsCPSwUa7vqew=s680-w680-h510", | ||||||
|       sightId: 17, |       sightId: 17, | ||||||
|  |       manualSightId: null, | ||||||
|  |       nearestSightId: null, | ||||||
|  |       returnTimer: null, | ||||||
|  |       lastUserActivity: Date.now(), | ||||||
|  |       firstLoad: true, | ||||||
|       stopName: "", |       stopName: "", | ||||||
|       watermarkLU: "", |       watermarkLU: "", | ||||||
|       watermarkRD: "", |       watermarkRD: "", | ||||||
| @@ -291,10 +316,10 @@ export default { | |||||||
|       routeProgress: null, |       routeProgress: null, | ||||||
|       routeId: null, |       routeId: null, | ||||||
|       selectedLang: localStorage.getItem("selectedLangRight") || "ru", |       selectedLang: localStorage.getItem("selectedLangRight") || "ru", | ||||||
|       showLangToggle: true, // видна «глобус»-кнопка |       showLangToggle: true, | ||||||
|       showLanguageOptions: false, // виден блок из трёх иконок |       showLanguageOptions: false, | ||||||
|       languageOptionsTimer: null, // таймер на 10 с |       languageOptionsTimer: null, | ||||||
|       langRevertTimer: null, // таймер на 30 с |       langRevertTimer: null, | ||||||
|       icons: { |       icons: { | ||||||
|         ru: `<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" fill="none" viewBox="0 0 28 28"> |         ru: `<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" fill="none" viewBox="0 0 28 28"> | ||||||
|   <path fill="#fff" d="M14 0C6.27 0 0 6.27 0 14s6.27 14 14 14 14-6.27 14-14S21.73 0 14 0Zm.117 19.57H11.62l-2.117-4.135H7.646v4.136H5.32V8.27h4.2c1.336 0 2.363.298 3.092.893.729.595 1.085 1.435 1.085 2.52 0 .77-.17 1.412-.502 1.931-.332.513-.84.928-1.517 1.23l2.444 4.62v.112l-.005-.006Zm9.391-3.855c0 1.237-.385 2.217-1.16 2.934-.776.718-1.832 1.08-3.174 1.08-1.341 0-2.368-.35-3.144-1.05-.776-.7-1.173-1.657-1.19-2.882V8.272h2.328v7.46c0 .741.175 1.278.53 1.616.356.339.846.508 1.47.508 1.307 0 1.972-.689 1.995-2.065V8.27h2.334v7.444h.011Z"/> |   <path fill="#fff" d="M14 0C6.27 0 0 6.27 0 14s6.27 14 14 14 14-6.27 14-14S21.73 0 14 0Zm.117 19.57H11.62l-2.117-4.135H7.646v4.136H5.32V8.27h4.2c1.336 0 2.363.298 3.092.893.729.595 1.085 1.435 1.085 2.52 0 .77-.17 1.412-.502 1.931-.332.513-.84.928-1.517 1.23l2.444 4.62v.112l-.005-.006Zm9.391-3.855c0 1.237-.385 2.217-1.16 2.934-.776.718-1.832 1.08-3.174 1.08-1.341 0-2.368-.35-3.144-1.05-.776-.7-1.173-1.657-1.19-2.882V8.272h2.328v7.46c0 .741.175 1.278.53 1.616.356.339.846.508 1.47.508 1.307 0 1.972-.689 1.995-2.065V8.27h2.334v7.444h.011Z"/> | ||||||
| @@ -310,7 +335,7 @@ export default { | |||||||
|       }, |       }, | ||||||
|       translations: { |       translations: { | ||||||
|         sights: { ru: "Достопримечательности", en: "Landmarks", zh: "景点" }, |         sights: { ru: "Достопримечательности", en: "Landmarks", zh: "景点" }, | ||||||
|         // при необходимости — другие подписи |         back: { ru: "Вернуться назад", en: "Back", zh: "返回" }, | ||||||
|       }, |       }, | ||||||
|     }; |     }; | ||||||
|   }, |   }, | ||||||
| @@ -352,6 +377,9 @@ export default { | |||||||
|         Object.entries(this.nextStopTransfers).filter(([, value]) => value) |         Object.entries(this.nextStopTransfers).filter(([, value]) => value) | ||||||
|       ); |       ); | ||||||
|     }, |     }, | ||||||
|  |     showBackButton() { | ||||||
|  |       return this.sightId !== this.nearestSightId; | ||||||
|  |     }, | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
|     t(key) { |     t(key) { | ||||||
| @@ -513,86 +541,14 @@ export default { | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     async openSightCardDetails(id) { |     async openSightCardDetails(id) { | ||||||
|       // закрыть, если нажали повторно |       this.manualSightId = id; | ||||||
|       if (this.selectedSightCardId === id) { |       this.sightId = id; | ||||||
|  |       this.showSightsList = false; | ||||||
|       this.selectedSightCardId = null; |       this.selectedSightCardId = null; | ||||||
|       this.cardDetail = null; |       this.cardDetail = null; | ||||||
|         return; |       this.resetReturnTimer(); | ||||||
|       } |       await this.fetchSightInfo(); | ||||||
|       this.selectedSightCardId = id; |       await this.fetchArticles(); | ||||||
|       this.cardDetail = null; |  | ||||||
|       this.resetSightsInactivityTimer(); |  | ||||||
|  |  | ||||||
|       try { |  | ||||||
|         const [detailRes, articlesRes] = await Promise.all([ |  | ||||||
|           axios.get(this.addLangParam(`${API_URL}/sight/${id}`)), |  | ||||||
|           axios.get(this.addLangParam(`${API_URL}/sight/${id}/article`)), |  | ||||||
|         ]); |  | ||||||
|  |  | ||||||
|         // Fetch media for every article |  | ||||||
|         const articlesWithMedia = await Promise.all( |  | ||||||
|           articlesRes.data.map(async (article) => { |  | ||||||
|             try { |  | ||||||
|               const mediaRes = await axios.get( |  | ||||||
|                 this.addLangParam(`${API_URL}/article/${article.id}/media`) |  | ||||||
|               ); |  | ||||||
|               return { ...article, media: mediaRes.data }; |  | ||||||
|             } catch (mediaErr) { |  | ||||||
|               console.error( |  | ||||||
|                 `Failed to fetch media for article ${article.id}:`, |  | ||||||
|                 mediaErr |  | ||||||
|               ); |  | ||||||
|               return { ...article, media: [] }; |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         ); |  | ||||||
|  |  | ||||||
|         // Console output: sight name, articles, and their media |  | ||||||
|         console.log("Sight clicked:", { |  | ||||||
|           name: detailRes.data.name, |  | ||||||
|           articles: articlesWithMedia, |  | ||||||
|         }); |  | ||||||
|  |  | ||||||
|         // Choose preview image: prefer the first article's first media, otherwise fall back to sight thumbnail |  | ||||||
|         let imageUrl = ""; |  | ||||||
|         if ( |  | ||||||
|           articlesWithMedia.length > 0 && |  | ||||||
|           articlesWithMedia[0].media && |  | ||||||
|           articlesWithMedia[0].media.length > 0 |  | ||||||
|         ) { |  | ||||||
|           const firstMediaId = articlesWithMedia[0].media[0].id; |  | ||||||
|           try { |  | ||||||
|             imageUrl = await this.getMediaBlobUrl(firstMediaId); |  | ||||||
|           } catch { |  | ||||||
|             imageUrl = this.addLangParam( |  | ||||||
|               `${API_URL}/media/${firstMediaId}/download` |  | ||||||
|             ); |  | ||||||
|           } |  | ||||||
|         } else if (detailRes.data.thumbnail) { |  | ||||||
|           try { |  | ||||||
|             imageUrl = await this.getMediaBlobUrl(detailRes.data.thumbnail); |  | ||||||
|           } catch { |  | ||||||
|             imageUrl = this.addLangParam( |  | ||||||
|               `${API_URL}/media/${detailRes.data.thumbnail}/download` |  | ||||||
|             ); |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         this.cardDetail = { |  | ||||||
|           name: detailRes.data.name, |  | ||||||
|           imageUrl, |  | ||||||
|           articles: articlesWithMedia, |  | ||||||
|         }; |  | ||||||
|         if (articlesWithMedia.length > 0) { |  | ||||||
|           this.selectedSightArticleId = articlesWithMedia[0].id; |  | ||||||
|           this.selectedSightArticleBody = articlesWithMedia[0].body; |  | ||||||
|         } else { |  | ||||||
|           this.selectedSightArticleId = null; |  | ||||||
|           this.selectedSightArticleBody = ""; |  | ||||||
|         } |  | ||||||
|       } catch (err) { |  | ||||||
|         console.error("Failed to load sight card details:", err); |  | ||||||
|       } |  | ||||||
|     }, |     }, | ||||||
|     async selectSightArticle(id) { |     async selectSightArticle(id) { | ||||||
|       this.selectedSightArticleId = id; |       this.selectedSightArticleId = id; | ||||||
| @@ -657,10 +613,12 @@ export default { | |||||||
|       }, 300_000); // 5 m |       }, 300_000); // 5 m | ||||||
|     }, |     }, | ||||||
|     handleUserActivity() { |     handleUserActivity() { | ||||||
|  |       this.lastUserActivity = Date.now(); | ||||||
|       if (this.showSightsList || this.cardDetail) |       if (this.showSightsList || this.cardDetail) | ||||||
|         this.resetSightsInactivityTimer(); |         this.resetSightsInactivityTimer(); | ||||||
|       this.resetArticleInactivityTimer(); |       this.resetArticleInactivityTimer(); | ||||||
|       this.resetLangRevertTimer(); |       this.resetLangRevertTimer(); | ||||||
|  |       if (this.returnTimer) this.resetReturnTimer(); | ||||||
|     }, |     }, | ||||||
|     selectArticle(id) { |     selectArticle(id) { | ||||||
|       this.resetArticleInactivityTimer(); |       this.resetArticleInactivityTimer(); | ||||||
| @@ -738,23 +696,41 @@ export default { | |||||||
|             newSightId = this.sights[1].id; |             newSightId = this.sights[1].id; | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|         if (newSightId && newSightId !== this.sightId) { |         if (newSightId) { | ||||||
|  |           if (this.firstLoad) { | ||||||
|  |             this.nearestSightId = newSightId; | ||||||
|             this.sightId = newSightId; |             this.sightId = newSightId; | ||||||
|             await this.fetchSightInfo(); |             await this.fetchSightInfo(); | ||||||
|             await this.fetchArticles(); |             await this.fetchArticles(); | ||||||
|  |             this.firstLoad = false; | ||||||
|  |             this.clearReturnTimer(); | ||||||
|  |             return; | ||||||
|  |           } | ||||||
|  |           if (this.nearestSightId !== newSightId) { | ||||||
|  |             this.nearestSightId = newSightId; | ||||||
|  |           } | ||||||
|  |           if (!this.manualSightId) { | ||||||
|  |             if (this.sightId !== this.nearestSightId) { | ||||||
|  |               const userActive = Date.now() - this.lastUserActivity < 15_000; // 15-сек. окно | ||||||
|  |               if (userActive) { | ||||||
|  |                 this.resetReturnTimer(); | ||||||
|  |               } else { | ||||||
|  |                 this.clearReturnTimer(); | ||||||
|  |                 this.sightId = this.nearestSightId; | ||||||
|  |                 await this.fetchSightInfo(); | ||||||
|  |                 await this.fetchArticles(); | ||||||
|  |               } | ||||||
|  |             } else { | ||||||
|  |               this.clearReturnTimer(); | ||||||
|  |             } | ||||||
|  |           } | ||||||
|         } |         } | ||||||
|         const nextStopId = response.data.routeProgress?.endStopId; |         const nextStopId = response.data.routeProgress?.endStopId; | ||||||
|         // console.log("Fetched next stop ID:", nextStopId); |  | ||||||
|         // console.log("Stops:", this.stops); |  | ||||||
|         if (nextStopId && this.stops) { |         if (nextStopId && this.stops) { | ||||||
|           const nextStop = this.stops.find((stop) => stop.id == nextStopId); |           const nextStop = this.stops.find((stop) => stop.id == nextStopId); | ||||||
|           // console.log("Fetched next stop ID:", nextStopId); |  | ||||||
|           // console.log("Matching stop:", nextStop); |  | ||||||
|           if (nextStop && nextStop.transfers) { |           if (nextStop && nextStop.transfers) { | ||||||
|             // console.log("Transfers at next stop:", nextStop.transfers); |  | ||||||
|             this.nextStopTransfers = nextStop.transfers; |             this.nextStopTransfers = nextStop.transfers; | ||||||
|           } else { |           } else { | ||||||
|             // console.log("No transfers found at next stop"); |  | ||||||
|             this.nextStopTransfers = null; |             this.nextStopTransfers = null; | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
| @@ -762,6 +738,29 @@ export default { | |||||||
|         console.error("Error fetching geolocation context:", error); |         console.error("Error fetching geolocation context:", error); | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     resetReturnTimer() { | ||||||
|  |       this.clearReturnTimer(); | ||||||
|  |       this.returnTimer = setTimeout(() => { | ||||||
|  |         this.returnToNearestSight(); | ||||||
|  |       }, 90_000); | ||||||
|  |     }, | ||||||
|  |     clearReturnTimer() { | ||||||
|  |       if (this.returnTimer) { | ||||||
|  |         clearTimeout(this.returnTimer); | ||||||
|  |         this.returnTimer = null; | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     returnToNearestSight() { | ||||||
|  |       if (!this.nearestSightId) return; | ||||||
|  |       this.manualSightId = null; | ||||||
|  |       this.sightId = this.nearestSightId; | ||||||
|  |       this.clearReturnTimer(); | ||||||
|  |       this.showSightsList = false; | ||||||
|  |       this.selectedSightCardId = null; | ||||||
|  |       this.cardDetail = null; | ||||||
|  |       this.fetchSightInfo(); | ||||||
|  |       this.fetchArticles(); | ||||||
|  |     }, | ||||||
|     selectLetter(letter) { |     selectLetter(letter) { | ||||||
|       const anchorArr = this.$refs[`letter-${letter}`]; |       const anchorArr = this.$refs[`letter-${letter}`]; | ||||||
|       const anchor = anchorArr ? anchorArr[0] : null; |       const anchor = anchorArr ? anchorArr[0] : null; | ||||||
| @@ -818,6 +817,7 @@ export default { | |||||||
|   async mounted() { |   async mounted() { | ||||||
|     await this.fetchSights(); |     await this.fetchSights(); | ||||||
|     await this.fetchGeolocationContext(); |     await this.fetchGeolocationContext(); | ||||||
|  |     this.nearestSightId = this.sightId; | ||||||
|     this.geolocationInterval = setInterval(() => { |     this.geolocationInterval = setInterval(() => { | ||||||
|       this.fetchGeolocationContext(); |       this.fetchGeolocationContext(); | ||||||
|     }, 1000); |     }, 1000); | ||||||
|   | |||||||
							
								
								
									
										373
									
								
								src/icons/spb-gerb.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										373
									
								
								src/icons/spb-gerb.svg
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| After Width: | Height: | Size: 176 KiB | 
		Reference in New Issue
	
	Block a user