1document.addEventListener("DOMContentLoaded", () => { 2 3 // ----------------------------- 4 // POPULAR DESTINATIONS 5 // ----------------------------- 6 fetch("/api/analytics/top?limit=5") 7 .then(r => r.json()) 8 .then(data => { 9 const container = document.getElementById("popular-widget"); 10 if (!container) return; 11 12 if (!data.length) { 13 container.innerHTML = "<div class='text-muted p-4 text-center'>No data available.</div>"; 14 return; 15 } 16 17 container.innerHTML = ` 18 <div class="list-group list-group-flush glossy-list"> 19 ${data.map(row => ` 20 <a href="/destinations/${row.iata}" 21 data-iata="${row.iata}" 22 data-city="${row.city}" 23 data-country="${row.country}" 24 class="list-group-item list-group-item-action border-0 py-3 px-4 d-flex justify-content-between align-items-center glossy-item mb-1"> 25 <div class="d-flex align-items-center"> 26 <div class="destination-icon me-3"> 27 <i class="bi bi-geo-alt-fill text-primary"></i> 28 </div> 29 <div class="destination-info"> 30 <div class="fw-bold city-name text-dark-emphasis">${row.city}</div> 31 <div class="extra-small text-muted text-uppercase tracking-wider">${row.iata}</div> 32 </div> 33 </div> 34 <div class="analytics-badge d-flex align-items-center"> 35 <span class="badge rounded-pill bg-primary-subtle text-primary border border-primary-subtle px-3 py-2"> 36 <i class="bi bi-mouse3-fill me-1"></i> ${row.total_clicks} 37 </span> 38 </div> 39 </a> 40 `).join("")} 41 </div> 42 `; 43 }) 44 .catch(err => { 45 console.error("Error loading top destinations:", err); 46 const container = document.getElementById("popular-widget"); 47 if (container) container.innerHTML = "<div class='text-danger p-4 text-center small'>Failed to load data.</div>"; 48 }); 49 50 51 // ----------------------------- 52 // TRENDING DESTINATIONS 53 // ----------------------------- 54 fetch("/api/analytics/trending?limit=5") 55 .then(r => r.json()) 56 .then(data => { 57 const container = document.getElementById("trending-widget"); 58 if (!container) return; 59 60 if (!data.length) { 61 container.innerHTML = "<div class='text-muted p-4 text-center small'>No trending destinations today.</div>"; 62 return; 63 } 64 65 container.innerHTML = ` 66 <div class="list-group list-group-flush glossy-list"> 67 ${data.map(row => { 68 let badgeClass = "bg-secondary-subtle text-secondary"; 69 let arrow = "bi-dash"; 70 let colorClass = "text-secondary"; 71 72 if (row.change > 0) { 73 badgeClass = "bg-success-subtle text-success"; 74 arrow = "bi-caret-up-fill"; 75 colorClass = "text-success"; 76 } else if (row.change < 0) { 77 badgeClass = "bg-danger-subtle text-danger"; 78 arrow = "bi-caret-down-fill"; 79 colorClass = "text-danger"; 80 } 81 82 return ` 83 <a href="/destinations/${row.iata}" 84 data-iata="${row.iata}" 85 data-city="${row.city}" 86 data-country="${row.country}" 87 class="list-group-item list-group-item-action border-0 py-2 px-4 d-flex justify-content-between align-items-center glossy-item mb-1"> 88 <div class="d-flex align-items-center"> 89 <div class="destination-icon me-3"> 90 <i class="bi bi-lightning-fill text-warning"></i> 91 </div> 92 <div class="destination-info"> 93 <div class="fw-bold city-name text-dark-emphasis">${row.city}</div> 94 <div class="extra-small text-muted text-uppercase tracking-wider">${row.iata}
94</div> 95 </div> 96 </div> 97 <div class="analytics-badge d-flex align-items-center"> 98 <span class="badge rounded-pill ${badgeClass} border border-opacity-10 px-3 py-2 d-flex align-items-center"> 99 <i class="bi ${arrow} me-1"></i> ${Math.abs(row.change)} 100 </span> 101 </div> 102 </a> 103 `; 104 }).join("")} 105 106 </div> 107 `; 108 }) 109 .catch(err => { 110 console.error("Error loading trending destinations:", err); 111 const container = document.getElementById("trending-widget"); 112 if (container) container.innerHTML = "<div class='text-danger p-4 text-center small'>Failed to load data.</div>"; 113 }); 114 115});
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.