PageSourceSearch

https://pewneauto.pl/assets/common/js/map-KcitWIx.js

js pewneauto.pl collected 2026-10-08 04:44:35 UTC 8,144 bytes, 267 lines download raw bytes

1import { helpers } from './helpers.js';
2import { settings } from './settings.js';
3import { loadGoogleMaps } from './gmapsLoader.js';
4import { setMarkersManager, getMarkersManager, MapMarkersManager, showDealerDetails, showDealerOffers, updateDealersList, resetDealerSearch, locationFieldAutocomplete, highlightRowOnDealerList } from './mapHelpers.js';
5
6export const map = (() => {
7
8  async function initMap( mapId) {
9    const mapContainer = document.querySelector( mapId );
10    if (!mapContainer) return;
11
12    // sanity-check configu
13    if (
14      !window.SP.mapConfig?.MAP_KEY ||
15      !Array.isArray(window.SP.mapConfig.dealersData) ||
16      !window.SP.mapConfig.dealersData.length
17    ) {
18      console.warn('Map init error – invalid or missing map data');
19      return;
20    }
21
22    // load gmap script
23    await loadGoogleMaps(window.SP.mapConfig.MAP_KEY);
24
25    const map = new google.maps.Map(mapContainer, {
26      mapId: 'dealers-map',
27      center: settings.location.initial,
28      zoom: settings.location.initial.zoom,
29      disableDefaultUI: true,
30      gestureHandling: 'cooperative',
31    });
32
33    // save initial dealers data for reset
34    window.SP.mapConfig.initialDealersData = [...window.SP.mapConfig.dealersData];
35
36    const markers = new MapMarkersManager(map);
37    setMarkersManager(markers);
38
39    // put markers on map
40    markers.add(window.SP.mapConfig.dealersData, (dealer) => {
41
42      switch (mapId) {
43        case '#dealer-map':
44          showDealerDetails(dealer, markers);
45          highlightRowOnDealerList(dealer);
46          break;
47
48        case '#offer-map':
49          showDealerOffers(dealer, markers);          
50          break;
51      }      
52    });
53
54    if( mapId == '#offer-map'){
55      const backBtn = document.querySelector('[dealer-back]');
56      const dialog = backBtn.closest('dialog');
57
58      backBtn.addEventListener('click', () => {
59        helpers.clearDialogTemplate(dialog);
60        dialog.close();
61
62        // Back to the view the page opens with. Recomputed from the markers, not replayed from
63        // defaultView: saveDefaultView() reads getCenter()/getZoom() right after fitBounds(), which
64        // Google Maps applies asynchronously, so that snapshot holds the pre-fit position.
65        markers.fitToMarkers();
66        markers.unhighlight();
67      });
68    }
69
70    // fit view for all markers
71    markers.fitToMarkers();
72
73
74    // click on dealer row in list
75    document.addEventListener('click', (e) => {
76      const row = e.target.closest('[show-dealer-details]');
77      if (!row) return;
78      
79      const dealerId = row.getAttribute('show-dealer-details');
80      const isActive = row.classList.contains('active');
81
82      const dealer = window.SP.mapConfig.dealersData?.find(
83        (d) => d.id == dealerId
84      );
85
86      if (!dealer ){
87        console.warn('Dealer not found in mapConfig.dealersData')
88        return;
89      }
90
91      // clear content
92      document.querySelector('.find-dealer__details').innerHTML = '';
93      // unselect all rows
94      document.querySelectorAll('[show-dealer-details].active').forEach(el => el.classList.remove('active'));
95      document.querySelectorAll('[show-dealer-details]').forEach(el => el.setAttribute('aria-selected' , false));
96
97      if (isActive) {
98        markers.restoreDefaultView();
99      } else {
100        showDealerDetails(dealer, markers);
101      }
102    });
103
104
105    // click on 'find dealers near me' btn
106    const btn = document.querySelector('[find-dealer-near-user]');
107    if (btn) {
108      btn.addEventListener('click', () => {
109        if (!navigator.geolocation || btn.disabled) return;
110
111        btn.disabled = true;
112        navigator.geolocation.getCurrentPosition(
113          (position) => {
114            const query = `${position.coords.latitude},${position.coords.longitude}`;
115
116            const queries = {
117              queryValue: query,
118              rangeValue: '100 km'
119            };
120
121            updateDealersList(queries);
122            btn.disabled = false;
123          },
124          () => {
125            btn.disabled = false;
126          }
127        );
128      });
129    }
130
131
132    // click on 'reset search' btn
133    const resetBtn = document.querySelector('[reset-dealer-search]');
134    if (resetBtn) {
135      resetBtn.addEventListener('click', () => {
136        resetDealerSearch(markers, mapId);
137      });
138    }
139
140  }
141
142
143
144  /**
145     * Initializes Google Places autocomplete integration.
146     *
147     * Attaches the autocomplete to the location input field, retrieves
148     * location details via API, and updates a hidden field with latitude/longitude.
149     *
150     * @function initGooglePlaces
151     */
152    function initGooglePlaces(mapId) {
153      const mapContainer = document.querySelector( mapId );
154      if (!mapContainer) return;
155
156      const searchForm = document.querySelector('.find-dealer__control__search');
157      if (!searchForm) return;
158
159      const locationInput = searchForm.querySelector('[name="location"]');
160      const queryInput = searchForm.querySelector('[name="query"]');
161      const rangeInput = searchForm.querySelector('[name="range"]');
162      
163      const formSubmit = searchForm.querySelector('button[type="submit"]');
164
165      if( !locationInput || !queryInput || !rangeInput ) return;
166
167      // Reset queryInput when typing
168      locationInput.addEventListener('input', () => {
169        queryInput.value = '';
170      });
171
172      // Clear input button
173      const clearBtn = searchForm.querySelector('[clear-location-input]');
174      if (clearBtn) {
175        const updateClearBtn = () => {
176          clearBtn.hidden = !locationInput.value.trim();
177        };
178
179        locationInput.addEventListener('input', updateClearBtn);
180        locationInput.addEventListener('update', updateClearBtn);
181
182        clearBtn.addEventListener('click', () => {
183          locationInput.value = '';
184          queryInput.value = '';
185          clearBtn.hidden = true;
186          locationInput.dispatchEvent(new CustomEvent('clear'));
187          locationInput.focus();
188        });
189      }
190  
191      // Attach autocomplete
192      locationFieldAutocomplete(locationInput, (loc) => {
193        if (!loc?.id || !loc?.value) return;
194  
195        // Prepare query params
196        const params = new URLSearchParams({
197          locationId: loc.id,
198          locationName: loc.value,
199        }).toString();
200  
201        locationInput.classList.add('loading');
202        formSubmit.classList.add('disabled');
203  
204        // Fetch detailed data
205        fetch(`${location.origin}
205/${settings.endpoints.locationDetails}?${params}`, {
206          method: 'GET',
207          headers: { 'Accept': 'application/json' },
208        })
209          .then((res) => res.json())
210          .then((json) => {
211            const data = json.data;
212  
213            // extract lat/lng
214            if (data.result?.geometry) {
215              const location = data.result.geometry.location?.lat + ',' + data.result.geometry.location?.lng;
216              queryInput.value = location; // Update hidden field with coord
217            }
218          })
219          .catch((err) => {
220            console.error('Location details request failed:', err);
221          })
222          .finally(() => {
223            locationInput.classList.remove('loading');
224            formSubmit.classList.remove('disabled');
225          });
226      });
227
228      if (searchForm.dataset.jsEventInitialized === 'true') {
229        return;
230      }
231
232      // Handles search form submission via GET fetch request.
233      searchForm.addEventListener('submit', (e) => {
234        e.preventDefault();
235
236        const queries = {
237          'locationValue' : locationInput.value.trim(),
238          'queryValue' : queryInput.value.trim(),
239          'rangeValue' : rangeInput.value.trim()
240        }
241
242        if ( !queries.queryValue && !queries.locationValue ) {
243          resetDealerSearch(getMarkersManager(), mapId);
244          return;
245        }
246
247        updateDealersList( queries );
248
249      });
250
251      searchForm.dataset.jsEventInitialized = 'true';
252    }
253
254  function setup( mapId ) {
255    initMap( mapId );
256    initGooglePlaces( mapId );
257  }
258
259  return {
260    setup,
261    initMap,
262    initGooglePlaces,
263  };
264})();
265
266window.SP = window.SP || {};
267window.SP.map = map;

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.