PageSourceSearch

https://www.kitepharma.com/Areas/Kite/Content/mapbox/assets/mapbox/js/details.js

js kitepharma.com collected 2026-10-02 06:22:00 UTC 11,075 bytes, 360 lines download raw bytes

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.