/* Minification failed. Returning unminified contents. (4,6): run-time error JS1004: Expected ';' (9,27): run-time error JS1004: Expected ';' (28,23): run-time error JS1004: Expected ';' (51,6): run-time error JS1004: Expected ';' (58,27): run-time error JS1004: Expected ';' (78,23): run-time error JS1004: Expected ';' (148,6): run-time error JS1004: Expected ';' (149,35): run-time error JS1004: Expected ';' (150,42): run-time error JS1004: Expected ';' (178,61-63): run-time error JS1006: Expected ')': => (178,60): run-time error JS1004: Expected ';' (198,26): run-time error JS1004: Expected ';' (209,39): run-time error JS1004: Expected ';' (219,6-7): run-time error JS1195: Expected expression: ) (222,40-42): run-time error JS1006: Expected ')': => (222,39): run-time error JS1004: Expected ';' (229,39): run-time error JS1004: Expected ';' (240,6-7): run-time error JS1195: Expected expression: ) (243,6): run-time error JS1004: Expected ';' (244,35): run-time error JS1004: Expected ';' (245,42): run-time error JS1004: Expected ';' (267,61-63): run-time error JS1006: Expected ')': => (267,60): run-time error JS1004: Expected ';' (288,26): run-time error JS1004: Expected ';' (299,39): run-time error JS1004: Expected ';' (309,6-7): run-time error JS1195: Expected expression: ) (312,40-42): run-time error JS1006: Expected ')': => (312,39): run-time error JS1004: Expected ';' (314,39): run-time error JS1004: Expected ';' (325,6-7): run-time error JS1195: Expected expression: ) (328,6): run-time error JS1004: Expected ';' (329,26): run-time error JS1004: Expected ';' (341,6): run-time error JS1004: Expected ';' (372,6): run-time error JS1004: Expected ';' (373,56): run-time error JS1004: Expected ';' (422,35): run-time error JS1004: Expected ';' (475,6): run-time error JS1004: Expected ';' (478,35): run-time error JS1004: Expected ';' (517,6): run-time error JS1004: Expected ';' (544,6): run-time error JS1004: Expected ';' (545,30): run-time error JS1004: Expected ';' (620,13-16): run-time error JS1009: Expected '}': ... (622,9-14): run-time error JS1006: Expected ')': const (621,10): run-time error JS1004: Expected ';' (626,6-7): run-time error JS1195: Expected expression: ) (627,1-2): run-time error JS1002: Syntax error: } */ // open contact modal /////////////////////////// let contactModal; async function openContactModal(volunteerCompositeID, contactMethod, isUpdate = false, itemID = 0) { if (!contactModal) { contactModal = new bootstrap.Modal(document.getElementById('contactModal')); } const response = await fetch(`/VPR/Account/OpenModal`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ compositeIDString: volunteerCompositeID, contactMethod, isUpdate, itemID }) }); if (!response.ok) { handleResponseError(response); return; } // replace modal contents const data = await response.text(); const contactModalContainer = document.getElementById('contactModal'); contactModalContainer.innerHTML = data; // set submit type const form = document.getElementById('contactForm'); form.dataset.submitType = isUpdate ? 'Update' : 'Add'; // adjust modal width if (contactMethod == "languages" || contactMethod == "specialties") { contactModalContainer.classList.add("modal-xl"); } else { contactModalContainer.classList.remove("modal-xl"); } // show the modal contactModal.show(); } // open marker modal /////////////////////////// let markerModal; async function openMarkerModal(lat, lng, isUpdate = false, markerID = 0) { if (!markerModal) { markerModal = new bootstrap.Modal(document.getElementById('markerModal')); } const compositeIDString = document.getElementById('markerModal').dataset.compositeId; const response = await fetch(`/VPR/Account/OpenMarkerModal`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ compositeIDString, lat, lng, isUpdate, markerID }) }); if (!response.ok) { handleResponseError(response); return; } // replace modal contents const data = await response.text(); const markerModalContainer = document.getElementById('markerModal'); markerModalContainer.innerHTML = data; // set submit type const form = document.getElementById('markerForm'); form.dataset.submitType = isUpdate ? 'Update' : 'Add'; // show the modal markerModal.show(); } // confirm deletion /////////////////////////// let deleteModal; function confirmDeletion(deleteType, itemID) { if (!deleteModal) { deleteModal = new bootstrap.Modal(document.getElementById('deleteModal')); } const modal = document.getElementById('deleteModal'); const modalBody = modal.querySelector('.modal-body'); const deleteButton = modal.querySelector('.modal-footer button[type="submit"]'); modal.dataset.deleteType = deleteType; modal.dataset.deleteId = itemID; modalBody.textContent = `Are you sure you want to delete this ${deleteType}?`; deleteButton.textContent = `Delete ${deleteType}`; deleteModal.show(); }; // map - Google Maps API /////////////////////////// let map; let geocoder; let mapMarkers = []; let infoWindow; let autocomplete; let searchInput; let placeAutocomplete; const mapId = 'DEMO_MAP_ID'; const CaliforniaLatLng = { lat: 37.483, lng: -119.4179 }; // roughly the center of California const californiaBounds = { north: 42.0095, south: 32.5343, east: -114.1315, west: -124.4096, }; const mapOptions = { center: CaliforniaLatLng, zoom: 6, streetViewControl: false, mapTypeControl: false, minZoom: 6, restriction: { latLngBounds: californiaBounds }, // disable clicks on other features clickableIcons: false, mapId } const autocompleteOptions = { bounds: californiaBounds, componentRestrictions: { country: 'us' }, fields: ['geometry'], strictBounds: true } async function initDashboardMap(markersJson) { const { Map, Polygon } = await google.maps.importLibrary('maps'); const { Place, Autocomplete } = await google.maps.importLibrary('places'); // initiate map map = new google.maps.Map(document.getElementById('map'), mapOptions); // initiate geocoder geocoder = new google.maps.Geocoder(); // initiate info window infoWindow = new google.maps.InfoWindow({ ariaLabel: 'Google Maps info window', position: map.getCenter() }); // FOR DEMONSTRATION PURPOSES ONLY /*showCaliforniaBoundary(map);*/ // set existing markers markersJson.forEach(marker => { placeMarker(marker.Latitude, marker.Longitude, marker.Radius, marker.ID); }); // initiate autocomplete searchInput = document.getElementById('map-search-input'); placeAutocomplete = new Autocomplete(searchInput, autocompleteOptions); // clear the form searchInput.value = ''; placeAutocomplete.addListener('place_changed', async () => { // coordinates if "California, USA" is chosen const coordinates = { lat: 36.778261, lng: -119.4179324 } // try to get place from autocomplete let place = placeAutocomplete.getPlace(); // reject if "California, USA" is chosen if (place.geometry && place.geometry.location) { const { lat, lng } = place.geometry.location; const isCaliforniaUSA = ((coordinates.lat == lat()) && (coordinates.lng == lng())); if (isCaliforniaUSA) { searchInput.value = ''; return notyf.error("Please choose a specific location within California."); } } if (!place.geometry || !place.geometry.location) { // try to get place details from input place = await getPlaceDetailsFromInput() // if no place found, throw error if (!place || !place.geometry) { return notyf.error("No map details available for the input."); } else { // else put address in the search box searchInput.value = place.formatted_address.replace(", USA", ""); } } // if in California, open marker modal const withinCalifornia = await isWithinCalifornia(place.geometry.location); if (withinCalifornia) { openMarkerModal(place.geometry.location.lat(), place.geometry.location.lng()); } else { notyf.open({ type: withinCalifornia.type, message: withinCalifornia.message }); searchInput.value = ''; } }); // add map click listener map.addListener("click", async (e) => { // close the infoWindow and abort to prevent click issues if (infoWindow.isOpen) { return infoWindow.close(); } // if in California, open marker modal const withinCalifornia = await isWithinCalifornia(e.latLng); if (withinCalifornia.success) { openMarkerModal(e.latLng.lat(), e.latLng.lng()); searchInput.value = `${withinCalifornia.cityOrCounty}, CA`; } else { notyf.open({ type: withinCalifornia.type, message: withinCalifornia.message }); searchInput.value = ''; } }); } async function initSearchMap() { const { Map, Polygon } = await google.maps.importLibrary('maps'); const { Place, Autocomplete } = await google.maps.importLibrary('places'); // initiate map map = new google.maps.Map(document.getElementById('map'), mapOptions); // initiate geocoder geocoder = new google.maps.Geocoder(); // initiate autocomplete searchInput = document.getElementById('map-search-input'); placeAutocomplete = new Autocomplete(searchInput, autocompleteOptions); // clear the form searchInput.closest('form').reset(); // override default Enter behavior searchInput.addEventListener('keydown', (e) => { if (e.key == "Enter") { e.preventDefault(); } }); // handle when user clicks a suggestion placeAutocomplete.addListener('place_changed', async () => { // coordinates if "California, USA" is chosen const coordinates = { lat: 36.778261, lng: -119.4179324 } // try to get place from autocomplete let place = placeAutocomplete.getPlace(); // reject if "California, USA" is chosen if (place.geometry && place.geometry.location) { const { lat, lng } = place.geometry.location; const isCaliforniaUSA = ((coordinates.lat == lat()) && (coordinates.lng == lng())); if (isCaliforniaUSA) { searchInput.value = ''; return notyf.error("Please choose a specific location within California."); } } // if no place selected, they pressed Enter if (!place.geometry || !place.geometry.location) { // try to get place details from input place = await getPlaceDetailsFromInput() // if no place found, throw error if (!place || !place.geometry) { return notyf.error("No map details available for the input."); } else { // else put address in the search box searchInput.value = place.formatted_address.replace(", USA", ""); } } // if in California, add marker const withinCalifornia = await isWithinCalifornia(place.geometry.location); if (withinCalifornia.success) { placeMarker(place.geometry.location.lat(), place.geometry.location.lng(), null, null, true); } else { notyf.open({ type: withinCalifornia.type, message: withinCalifornia.message }); searchInput.value = ''; } }); // add map click listener map.addListener("click", async (e) => { // if in California, open marker modal const withinCalifornia = await isWithinCalifornia(e.latLng); if (withinCalifornia.success) { searchInput.value = `${withinCalifornia.cityOrCounty}, CA`; placeMarker(e.latLng.lat(), e.latLng.lng(), null, null, true); } else { notyf.open({ type: withinCalifornia.type, message: withinCalifornia.message }); searchInput.value = ''; } }); } async function initDetailsMap(markersJson) { const { Map } = await google.maps.importLibrary('maps'); // initiate map map = new google.maps.Map(document.getElementById('map'), mapOptions); // set existing markers markersJson.forEach(marker => { placeMarker(marker.Latitude, marker.Longitude, marker.Radius, marker.ID, false, true); }); } // pick first suggestion when Enter is pressed async function getPlaceDetailsFromInput() { return new Promise((resolve, reject) => { let place = placeAutocomplete.getPlace(); if (!place || !place.geometry) { // if no place is selected, use input value to get predictions const autocompleteService = new google.maps.places.AutocompleteService(); autocompleteService.getPlacePredictions({ input: searchInput.value }, (placePredictions, status) => { if (status !== google.maps.places.PlacesServiceStatus.OK || placePredictions.length === 0) { reject('No place details found for the input.'); return; } // use the first prediction to get the place details const placesService = new google.maps.places.PlacesService(map); placesService.getDetails({ placeId: placePredictions[0].place_id }, (placeDetails, status) => { if (status !== google.maps.places.PlacesServiceStatus.OK) { reject('No place details found for the input.'); } else { resolve(placeDetails); } }); }); } else { // a place is already selected resolve(place); } }); } // place marker /////////////////// async function placeMarker(lat, lng, radius = 0, markerID = 0, searchPage = false, detailsPage = false) { const { AdvancedMarkerElement, PinElement } = await google.maps.importLibrary("marker"); // if search page, clear existing marker first if (searchPage && mapMarkers.length > 0) { mapMarkers.forEach(marker => { marker.marker.setMap(null); }); mapMarkers = []; } // custom glyph const parser = new DOMParser(); const glyphSvg = parser.parseFromString(getSvgGlyphString(), 'image/svg+xml').documentElement; glyphSvg.style.fill = '#ffffff'; // custom pin element const svgPinElement = new PinElement({ scale: 1.5, background: '#447766', borderColor: '#194949', glyph: glyphSvg }) const marker = new google.maps.marker.AdvancedMarkerElement({ position: { lat, lng }, map, content: svgPinElement.element }); // if NOT search page, add radius circle let radiusCircle; if (!searchPage) { // add radius circle const radiusInMeters = radius * 1609.3; radiusCircle = new google.maps.Circle({ strokeColor: "#447766", strokeOpacity: 0.8, strokeWeight: 2, fillColor: "#447766", fillOpacity: 0.35, clickable: false, map, center: { lat, lng }, radius: radiusInMeters }); } // if Dashboard page, add listener for infoWindow if (!searchPage && !detailsPage) { // get city or county const locationInfo = await getLocationInfo(lat, lng); // open infoWindow on click marker.addListener('click', () => { const latestRadius = mapMarkers.filter(marker => marker.id == markerID)[0].radius; infoWindow.setContent(buildMarkerContent(lat, lng, latestRadius, markerID)); const header = document.createElement('p'); header.classList.add('h6', 'my-0', 'me-2'); header.textContent = `${locationInfo}, CA`; infoWindow.setHeaderContent(header); infoWindow.open({ map, shouldFocus: false }); }); } // push marker to array mapMarkers.push({ id: markerID, radius, marker, radiusCircle }) } // build marker content ///////////////////////// function buildMarkerContent(lat, lng, radius, markerID) { const content = document.createElement("div"); content.classList.add("marker"); content.dataset.markerId = markerID; const svgGlyphString = getSvgGlyphString(); content.innerHTML = `
${getSvgMarkerIconString()}

Radius: ${radius} mi

`; return content; } // verify is within California async function isWithinCalifornia(latLng) { const isWithinCaliforniaBounds = getIsWithinCaliforniaBounds(latLng); if (isWithinCaliforniaBounds) { const cityOrCounty = await getLocationInfo(latLng.lat(), latLng.lng()); if (cityOrCounty) { return { success: true, cityOrCounty } } else { // has no location information return { success: false, type: 'warning', message: 'Too remote. No location information found.' } } } else { // not in California return { success: false, type: 'error', message: 'You must select a location within California.' } } } // is within California bounds //////////////////////////////// function getIsWithinCaliforniaBounds(latLng) { const { lat, lng } = latLng; // California's perimeter const caCoordinates = [ [32.718159, -114.535442], // southeastern point [34.565561, -114.161907], // upper southeastern point [39.032154, -119.962688], // mid eastern point [41.988238, -119.984661], // northeastern point [41.971984, -124.291301], // northwestern point [40.334148, -124.401165], // lower northwestern point [37.862015, -123.126751], // mid western point [34.493153, -120.512005], // upper southwestern point [32.496046, -117.018352], // southwestern point [32.718159, -114.535442] // back to start ]; const caPolygon = turf.polygon([caCoordinates]); const clickPoint = turf.point([lat(), lng()]); return turf.booleanPointInPolygon(clickPoint, caPolygon); } // get location info ///////////////////// async function getLocationInfo(lat, lng) { return new Promise((resolve, reject) => { geocoder.geocode({ location: { lat, lng } }, (results, status) => { if (status === 'OK' && results[0]) { const addressComponents = results[0].address_components; let city = ''; let county = ''; addressComponents.forEach(component => { if (component.types.includes('locality')) { city = component.long_name; } if (component.types.includes('administrative_area_level_2')) { county = component.long_name; } }); resolve(city || county); } else { console.log('Geocoder failed due to: ' + status); resolve('Unknown location'); } }); }); } // FOR DEMONSTRATION PURPOSES ONLY async function showCaliforniaBoundary(map) { const { Polygon } = await google.maps.importLibrary("maps"); const californiaCoordinates = [ { lat: 32.718159, lng: -114.535442 }, // southeastern point { lat: 34.565561, lng: -114.161907 }, // upper southeastern point { lat: 39.032154, lng: -119.962688 }, // mid eastern point { lat: 41.988238, lng: -119.984661 }, // northeastern point { lat: 41.971984, lng: -124.291301 }, // northwestern point { lat: 40.334148, lng: -124.401165 }, // lower northwestern point { lat: 37.862015, lng: -123.126751 }, // mid western point { lat: 34.493153, lng: -120.512005 }, // upper southwestern point { lat: 32.496046, lng: -117.018352 }, // southwestern point { lat: 32.718159, lng: -114.535442 } // back to start ]; const californiaPolygon = new google.maps.Polygon({ paths: californiaCoordinates, strokeColor: '#3388ff', strokeOpacity: 0.8, strokeWeight: 2, fillColor: '#3388ff', fillOpacity: 0.35 }); californiaPolygon.setMap(map); } // get SVG glyph string ///////////////////////// function getSvgGlyphString() { return ` `; } // get SVG marker icon string ////////////////////////////// function getSvgMarkerIconString() { return ` `; }; document.addEventListener('DOMContentLoaded', () => { initiateSearchListener(); }) function initiateSearchListener() { const searchForm = document.getElementById('searchForm'); searchForm.addEventListener('submit', (e) => { e.preventDefault(); const formData = new FormData(e.target); const entries = Object.fromEntries(formData.entries()); // abort if location not selected if (!mapMarkers.length) { return notyf.error("You must select a search location."); } // get marker position const markerPosition = mapMarkers[0].marker.position; // create params const searchData = { lat: markerPosition.lat, lng: markerPosition.lng, ...entries } const params = new URLSearchParams(searchData); // redirect to results page window.location.href = `/VPR/Search/Results?${params.toString()}`; }) } ;