1/** 2 * @file Updates the details section of the locator 3 */ 4 5import { getDirections, getTravelTimes } from './mapbox.js'; 6import { print } from './print.js'; 7import { createElement, updateTemplate } from './utilities.js'; 8 9/** 10 * 11 * @param {Object} map - Mapbox map 12 * @param {Object} theme - Theme object 13 * @param {Object} center - Center object 14 * @param {Array} selectedPlace - Selected place 15 */ 16export async function updateDetails(map, theme, center, selectedPlace, userFlow) { 17 const selectedCenter = center; 18 19 // Update URL to http endpoint of center details 20 21 const url = theme.centerApi(center); //configure from view 22 23 const centerDetails = await fetch(url).then((response) => response.json()); 24 25 const locator = document.getElementById('locator'); 26 locator.classList.add('opened'); 27 28 29 // Update details 30 const details = document.getElementById('locator-selected-details'); 31 details.innerHTML = ''; 32 details.setAttribute("data-cinfo", ""); 33 details.setAttribute("data-cdetails", ""); 34 35 const detailsElement = await getDetails(center, centerDetails, selectedPlace); 36 37 details.setAttribute("data-cinfo", JSON.stringify(center)); 38 details.setAttribute("data-cdetails", JSON.stringify(centerDetails));
39 details.append(detailsElement); 40 41 // Add print button 42 const printButton = document.querySelector('#locator-print'); 43 44 if (printButton) { 45 printButton.addEventListener('click', () => { 46 // https://github.com/mapbox/mapbox-gl-js/issues/1915 47 document.getElementById("locator-print").focus(); 48 print(map); 49 }); 50 } 51 52 // Add copyLink button 53 54 const copyButton = document.querySelector('#locator-copy-link'); 55 56 if (copyButton) { 57 copyButton.addEventListener('click', () => { 58 const currentURL = window.location.href; 59 document.getElementById("locator-copy-link").focus(); 60 navigator.clipboard.writeText(currentURL); 61 62 copyButton.innerHTML = copyButton.innerHTML.replace('Copy link', 'Copied!'); 63 64 setTimeout(() => { 65 copyButton.innerHTML = copyButton.innerHTML.replace('Copied!', 'Copy link'); 66 }, 3000); 67 }); 68 } 69 70 // Add line 71 if (selectedPlace) { 72 const directions = await getDirections(center.location, selectedPlace); 73 74 if (directions.routes[0]) { 75 map.getSource(`route`).setData({ 76 type: 'FeatureCollection', 77 features: [ 78 { 79 type: 'Feature', 80 properties: {}, 81 geometry: directions.routes[0].geometry 82 } 83 ] 84 }); 85 } 86 } 87 88 // console.log(userFlow); 89 90 // GTM event tracking when user clicks on the center name from the list 91 if (userFlow && userFlow == "centerName" && dictionary && dictionary.gtmListCenterName) { 92 let gtmListCenterName = Object.assign({}, dictionary.gtmListCenterName), 93 cInfo = JSON.parse(document.querySelector("#locator-selected-details").getAttribute("data-cinfo")), 94 cDetails = JSON.parse(document.querySelector("#locator-selected-details").getAttribute("data-cdetails")); 95 96 if (gtmListCenterName.eventLabel.indexOf("{CENTER NAME DETAILS}") >= 0) { 97 let milesHours = ""; 98 if (cInfo && cInfo.matrix) { 99 milesHours = " | " + (cInfo.matrix.miles || "") + " | " + (cInfo.matrix.minutes || ""); 100 } 101 let eventLabel = 102 cDetails.id + " | " 103 + cDetails.name + " | " 104 + cDetails.primaryAddress_State + " | " 105 + cDetails.primaryAddress_City + " | " 106 + cDetails.primaryAddress_Zip + " | " 107 + document.querySelector(".mapboxgl-ctrl-geocoder--input").value 108 + milesHours; 109 // [ID] | [Practice Name] | [Practice state abbreviation] | [Practice City] | [Practice Zip] | [Value available in search bar filed] | [miles] | [minutes] | Select List 110 gtmListCenterName.eventLabel = (gtmListCenterName.eventLabel.replace("{CENTER NAME DETAILS}", eventLabel)); 111 } else if (gtmListCenterName.eventLabel.indexOf("{Center Name}") >= 0) { 112 gtmListCenterName.eventLabel = (gtmListCenterName.eventLabel.replace("{Center Name}", cDetails.name)); 113 } else { 114 gtmListCenterName.eventLabel = centerDetails.primaryAddress_Zip; 115 } 116 117 if (dictionary.fnGTMPushData) { 118 dictionary.fnGTMPushData(gtmListCenterName); 119 } 120 } 121 122 // GTM event tracking when user clicks on the center pin from map 123 if (userFlow && userFlow == "centerPin" && dictionary && dictionary.gtmPin) { 124 let gtmPin = Object.assign({}, dictionary.gtmPin), 125 cDetails = JSON.parse(document.querySelector("#locator-selected-details").getAttribute("data-cdetails")); 126 if (gtmPin.eventLabel.indexOf("{CENTER PIN DETAILS}") >= 0) { 127 let eventLabel = 128 cDetails.id + " | " 129 + cDetails.name + " | " 130 + cDetails.primaryAddress_State + " | " 131 + cDetails.primaryAddress_City + " | " 132 + cDetails.primaryAddress_Zip; 133 // [ID] | [Practice Name] | [Practice state abbreviation] | [Practice City] | [Practice Zip] | [Value available in search bar filed] | Select Pin 134 gtmPin.eventLabel = (gtmPin.eventLabel.replace("{CENTER PIN DETAILS}", eventLabel)); 135 } else if (gtmPin.eventLabel.indexOf("{Pin number}") >= 0) { 136 gtmPin.eventLabel = (gtmPin.eventLabel.replace("{Pin number}", cDetails.primaryAddress_Zip)); 137 } else { 138 gtmPin.eventLabel = centerDetails.primaryAddress_Zip; 139 } 140 if (dictionary.fnGTMPushData) { 141 dictionary.fnGTMPushData(gtmPin); 142 } 143 } 144} 145 146/** 147 * 148 * @param {Object} center - Center object 149 * @param {Object} centerDetails - Center details object 150 * @param {Array} selectedPlace - Selected place 151 * @returns {Element} Details element 152 */ 153export async function getDetails(center, centerDetails, selectedPlace) { 154 const getAddress = () => { 155 if (selectedPlace) { 156 const origin = selectedPlace.slice().reverse().join(',');
157 const destination = centerDetails.primaryAddress; 158 159 return `https://www.google.com/maps/dir/?api=1&origin=${origin}&destination=${destination}`; 160 } 161 162 return `https://maps.google.com/?q=${centerDetails.primaryAddress}`; 163 }; 164 165 const getNote = (center) => { 166 if (!center.pediatric) return ``; 167 168 return dictionary.pediatricNote; 169 }; 170 171 let travelTimes = null; 172 173 if (selectedPlace) { 174 // travelTimes = await getTravelTimes(center.location, selectedPlace); 175 176 travelTimes = await getDirections(center.location, selectedPlace); 177 } 178 179 const template = updateTemplate(detailsTemplate, { 180 ...centerDetails, 181 182 pediatric: centerDetails.pediatric ? '*' : '', 183 travelTimes: getTravelTimesSection(travelTimes), 184 photo: getPhoto(centerDetails), 185 note: getNote(centerDetails), 186 factBox: getFactbox(centerDetails), 187 googleMapsAddress: getAddress(), 188 directions: centerDetails.directions || dictionary.missingNote, 189 consultation: centerDetails.consultation || dictionary.missingNote, 190 team: getTeam(centerDetails), 191 logo: getLogo(centerDetails) 192 }); 193 194 const element = createElement(template); 195 196 let inListMode = document.querySelector('.locator--mode-list'); 197 198 element.querySelectorAll('.locator__detail__section').forEach((section) => { 199 // Check if in list mode 200 201 const more = section.querySelector('.locator__detail__section__more'); 202 203 if (inListMode) { 204 section.classList.add('open'); 205 206 more.innerHTML = more.innerHTML.replace('more', 'less'); 207 } 208 209 if (more) { 210 more.addEventListener('click', () => { 211 section.classList.toggle('open'); 212 213 if (section.classList.contains('open')) { 214 more.innerHTML = more.innerHTML.replace('more', 'less'); 215 } 216 else { 217 more.innerHTML = more.innerHTML.replace('less', 'more'); 218 } 219 }); 220 } 221 }); 222 223 return element; 224} 225 226export function openAllPanels() { 227 let details = document.querySelector('.locator__detail'); 228 229 if (!details) return; 230 231 details.querySelectorAll('.locator__detail__section').forEach((section) => { 232 section.classList.add('open'); 233 234 const more = section.querySelector('.locator__detail__section__more'); 235 236 more.innerHTML = more.innerHTML.replace('more', 'less'); 237 }); 238} 239 240/** 241 * 242 * @param {string} image - Image URL 243 * @returns {string} HTML string 244 */ 245function getPhoto(center) { 246 if (!center.photo) return ''; 247 248 // return `<div class="locator__detail__photo" style="background-image: url(${center.photo})"></div>`; 249 return `<div class="locator__detail__photo"><img class="img-fluid" src="${center.photo}" /></div>`; 250} 251 252/** 253 * 254 * @param {Object} center - Center object 255 * @returns {string} HTML string 256 */ 257function getFactbox(center) { 258 const template = updateTemplate(factboxTemplate, { 259 ...center, 260 email: center.email ? `<a href="mailto:${center.email}" class="center-email">${dictionary.email}</a>` : 'â', 261 site: center.site ? `<a href='${center.site}' class='center-link mapbox-external-link' target='_blank'>${dictionary.link}</a>` : 'â' 262 }); 263 264 return template; 265} 266 267/** 268 * 269 * @param {Object} times - Travel times object 270 * @returns {string} HTML string 271 */ 272function getTravelTimesSection(times) { 273 if (!times) return ''; 274 275 // const distance = Math.floor((times.distances[0][1] / 1000) * 0.621); 276 // const totalminutes = Math.floor(times.durations[0][1] / 60); 277 278 const route = times.routes[0]; 279 280 if (!route) return ''; //No value return, BUG 281 282 let distance = 0; 283 let totalminutes = 0; 284 285 if (times.routes && times.routes[0]) { 286 const rawMiles = route.distance * 0.000621371; 287 const rawMinutes = route.duration / 60; 288 289 distance = Math.floor(rawMiles); 290 totalminutes = Math.floor(rawMinutes); 291 } 292 293 const hours = Math.floor(totalminutes / 60); 294 const minutes = totalminutes % 60; 295 296 let formattedHours = !hours 297 ? '' 298 : hours === 1 299 ? `${hours} ${dictionary['hour']}` 300 : `${hours} ${dictionary['hours']}`; 301 let formattedMinutes = !minutes 302 ? '' 303 : minutes === 1 304 ? `${minutes} ${dictionary['minute']}` 305 : `${minutes} ${dictionary['minutes']}`; 306 307 const template = updateTemplate(travelTimeTemplate, { 308 distance, 309 hours: formattedHours, 310 minutes: formattedMinutes 311 }); 312 313 return template; 314} 315 316/** 317 * 318 * @param {Object} data - Center object 319 * @returns {string} HTML string 320 */ 321function getTeam(data) { 322 if (!data.team) { 323 return `<p>${dictionary.missingNote}<p>`; 324 } 325 326 return data.team 327 .map((teammember) => { 328 const link = teammember.link 329 ? updateTemplate(teamLinkTemplate, { link: teammember.link }) 330 : ''; 331 332 const photo = teammember.photo 333 ? updateTemplate(teamPhotoTemplate, { photo: teammember.photo }) 334 : updateTemplate(teamPhotoTemplate, { photo: dictionary.careTeamPlaceHolderImage }); 335 336 const template = updateTemplate(teamTemplate, { 337 ...teammember, 338 339 primaryContact: teammember.primaryContact ? dictionary.primaryContact : '', 340 341 photo, 342 link 343 }); 344 345 return template; 346 }) 347 .join(''); 348} 349 350/** 351 * 352 * @param {string} image - Image URL 353 * @returns {string} HTML string 354 */ 355function getLogo(center) { 356 if (!center.logo) return ''; 357 358 // return `<div class="locator__detail__logo" style="background-image: url(${center.logo})"></div>`; 359 return `<div class="locator__detail__logo" style=""><img src="${center.logo}" alt="logo" /></div>`; 360}
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.