PageSourceSearch

https://www.edituratrei.ro/assets/js/api-courier-shipping.v2.js?v=1790273336

js edituratrei.ro collected 2026-09-24 18:09:10 UTC 53,961 bytes, 1,493 lines download raw bytes

1let lockerMap,
2    lockerCluster,
3    lockerPoints = [],
4    lockerMapLoaded = false;
5
6const fanboxIcon = L.icon({
7    iconUrl: `/assets/images/fanboxlockericon.png?v=${Date.now()}`,
8    iconSize: [64, 96],
9    iconAnchor: [32, 96],
10    popupAnchor: [0, -96],
11});
12
13const easyboxIcon = L.icon({
14    iconUrl: `/assets/images/easyboxlockericon.png?v=${Date.now()}`,
15    iconSize: [62, 80],
16    iconAnchor: [31, 80],
17    popupAnchor: [0, -80],
18});
19
20const dpdLockerIcon = L.icon({
21    iconUrl: `/assets/images/dpdlockericon.png?v=${Date.now()}`,
22    iconSize: [62, 80],
23    iconAnchor: [31, 80],
24    popupAnchor: [0, -80],
25});
26
27function resetLockerMapView() {
28    if (!lockerMap) return;
29    lockerMap.setView([44.4268, 26.1025], 13, {animate: false});
30}
31
32function openSelectedLockerPopupIfAny() {
33    const pickupInput = document.querySelector(".pickup-point");
34    const selectedValue = (pickupInput?.value || "").trim();
35    if (!selectedValue) return;
36
37    const parts = selectedValue.split("|||");
38    const routing = (parts[0] || "").trim();
39    const pickedId = (parts.length >= 4 ? parts[3] || "" : "").trim();
40
41    let selectedSlug = "";
42    let selectedType = "";
43    try {
44        const parsed = JSON.parse(
45            document.getElementById("shipping-locker-unic")?.value || "{}"
46        );
47        selectedSlug = parsed?.courierSlug || "";
48        selectedType = parsed?.courierType || "";
49    } catch (e) {
50    }
51
52    let found = null;
53
54    if (pickedId && selectedSlug) {
55        found = lockerPoints.find(
56            (p) =>
57                p.curier_slug === selectedSlug &&
58                String(p.curier_external_id || p.pickup_point_id || p.id || "") ===
59                String(pickedId)
60        );
61    }
62
63    if (!found && routing && selectedSlug) {
64        found = lockerPoints.find(
65            (p) =>
66                p.curier_slug === selectedSlug &&
67                String(p.curier_routing_location || "").trim() === routing
68        );
69    }
70
71    if (!found && routing) {
72        found = lockerPoints.find(
73            (p) => String(p.curier_routing_location || "").trim() === routing
74        );
75    }
76
77    if (!found) return;
78
79    if (!found._marker) {
80        const mk = createLockerMarker(found);
81        if (!mk) return;
82        addPopupToMarker(mk, found);
83        found._marker = mk;
84        lockerCluster.addLayer(mk);
85    }
86
87    const lat = parseFloat(found.curier_latitude);
88    const lng = parseFloat(found.curier_longitude);
89    if (!isFinite(lat) || !isFinite(lng)) return;
90
91    lockerMap.setView([lat, lng], 19, {animate: false});
92    found._marker.openPopup();
93}
94
95const lockerModal = document.getElementById("lockerMapModal");
96lockerModal.addEventListener("shown.bs.modal", async () => {
97    const loader = document.getElementById("locker-loader");
98    const searchInput = document.getElementById("lockerSearch");
99
100    if (!lockerMapLoaded) {
101        loader.style.display = "block";
102        if (searchInput) searchInput.classList.add("d-none");
103    }
104
105    let activeTab = document.querySelector(".courier-tab.active");
106
107    const pickupInput = document.querySelector(".pickup-point");
108    const selectedValue = pickupInput?.value.trim();
109
110    let slugFromInput = "";
111    let typeFromInput = "";
112
113    if (selectedValue) {
114        const lockerInput = document.getElementById("shipping-locker-unic");
115        if (lockerInput && lockerInput.value) {
116            try {
117                const parsed = JSON.parse(lockerInput.value);
118                slugFromInput = parsed?.courierSlug || "";
119                typeFromInput = parsed?.courierType || "";
120            } catch (err) {
121                console.warn("JSON parse fail", err);
122            }
123        }
124    }
125
126    if (activeTab) {
127        currentCourierSlug = activeTab.dataset.slug;
128        currentCourierType = activeTab.dataset.type;
129        lockerPoints = await fetchLockersForCourier(
130            currentCourierSlug,
131            currentCourierType
132        );
133    } else {
134        if (slugFromInput) {
135            currentCourierSlug = slugFromInput;
136            currentCourierType =
137                typeFromInput || (slugFromInput === "fancourier" ? "fanbox" : "locker");
138
139            lockerPoints = await fetchLockersForCourier(
140                currentCourierSlug,
141                currentCourierType
142            );
143        } else {
144            currentCourierSlug = "sameday";
145            currentCourierType = "locker";
146
147            lockerPoints = await fetchLockersForCourier(
148                currentCourierSlug,
149                currentCourierType
150            );
151        }
152    }
153
154    if (!lockerMap) {
155        lockerMap = L.map("lockerMap").setView([44.4268, 26.1025], 13);
156        L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png").addTo(
157            lockerMap
158        );
159        lockerCluster = L.markerClusterGroup();
160        lockerMap.addLayer(lockerCluster);
161        L.control
162            .locate({
163                position: "topleft",
164                flyTo: true,
165            })
166            .addTo(lockerMap);
167    }
168
169    lockerCluster.clearLayers();
170
171    lockerPoints.forEach((p) => {
172        if (p.curier_slug !== currentCourierSlug) return;
173
174        if (!p._marker) {
175            p._marker = createLockerMarker(p);
176        }
177        if (!p._marker) return;
178
179        addPopupToMarker(p._marker, p);
180        lockerCluster.addLayer(p._marker);
181    });
182
183    loader.style.display = "none";
184    if (searchInput) searchInput.classList.remove("d-none");
185
186    lockerMapLoaded = true;
187    lockerMap.invalidateSize();
188
189    setTimeout(() => {
190        openSelectedLockerPopupIfAny();
191    }, 150);
192});
193
194document.getElementById("lockerSearch").addEventListener("input", async () => {
195    const searchInput = document.getElementById("lockerSearch");
196    const val = searchInput.value.trim();
197
198    if (val === "") {
199        document.getElementById("lockerSuggestions").innerHTML = "";
200
201        const activeTab = document.querySelector(".courier-tab.active");
202        if (!activeTab) {
203            lockerCluster.clearLayers();
204            const allCurieri = [
205                {slug: "fancourier", type: "fanbox"},
206                {slug: "sameday", type: "locker"},
207                {slug: "dpd", type: "locker"},
208            ];
209            lockerPoints = [];
210            for (const c of allCurieri) {
211                const result = await fetchLockersForCourier(c.slug, c.type);
212                lockerPoints = lockerPoints.concat(result);
213            }
214            lockerPoints.forEach((p) => {
215                const marker = createLockerMarker(p);
216                if (!marker) return;
217                addPopupToMarker(marker, p);
218                lockerCluster.addLayer(marker);
219            });
220        }
221    }
222});
223
224async function fetchLockersForCourier(slug, type) {
225    const response = await fetch(
226        `/api-couriers/v2/api-get-courier-pickup-points.php?slug=${slug}&type=${type}`
227    );
228    const data = await response.json();
229    const points = data.pickup_points || [];
230
231    points.forEach((p) => {
232        p.curier_slug = slug;
233        p.curier_type = type;
234    });
235
236    const unique = {};
237    points.forEach((p) => {
238        const uid = String(
239            p.curier_external_id ||
240            p.pickup_point_id ||
241            p.id ||
242            p.curier_routing_location
243        );
244        unique[`${slug}::${type}::${uid}`] = p;
245    });
246    return Object.values(unique);
247}
248
249function addPopupToMarker(marker, p) {
250    p._marker = marker;
251
252    const pickupInput = document.querySelector(".pickup-point");
253    const selectedValue = pickupInput?.value.trim() || "";
254    let isAlreadySelected = false;
255
256    if (selectedValue) {
257        const parts = selectedValue.split("|||");
258        const selectedRouting = (parts[0] || "").trim();
259        const selectedId = (parts.length >= 4 ? parts[3] || "" : "").trim();
260
261        let selectedSlug = "";
262        try {
263            const parsed = JSON.parse(
264                document.getElementById("shipping-locker-unic")?.value || "{}"
265            );
266            selectedSlug = parsed?.courierSlug || "";
267        } catch (e) {
268        }
269
270        const pId = String(p.curier_external_id || p.pickup_point_id || p.id || "");
271        const pRouting = String(p.curier_routing_location || "").trim();
272
273        if (selectedId && selectedSlug && pId) {
274            isAlreadySelected =
275                p.curier_slug === selectedSlug && pId === String(selectedId);
276        } else {
277            isAlreadySelected = pRouting === selectedRouting;
278        }
279    }
280
281    const btnLabel = isAlreadySelected ? "Locker ales" : "Alege acest Locker";
282    const btnClass = isAlreadySelected ? "btn-success" : "btn-primary";
283
284    const popupContent = `
285  <div style="font-size: 14px; line-height: 1.4;">
286    <strong>${p.curier_name}</strong><br>
287    ${p.curier_address_street || ""} Nr. ${p.curier_address_street_no || ""}<br>
288    ${p.curier_address_locality}, ${p.curier_address_county}<br>
289    <a href="https://www.google.com/maps/search/?api=1&query=${
290        p.curier_latitude
291    },${
292        p.curier_longitude
293    }" target="_blank" style="font-size:12px;color:#007bff;">
293Deschide în Google Maps</a><br>
294    <button class="btn btn-sm ${btnClass} select-locker-btn">
295      ${btnLabel}
296    </button>
297  </div>
298`;
299
300    marker.bindPopup(popupContent);
301    marker.off("popupopen");
302    marker.on("popupopen", () => {
303        const popupEl = marker.getPopup().getElement();
304        const btn = popupEl?.querySelector(".select-locker-btn");
305        if (btn) {
306            btn.onclick = null;
307            btn.onclick = () => {
308                const pickupInput = document.querySelector(".pickup-point");
309                const countyLocalityInput = document.querySelector(
310                    ".pickup-county-locality"
311                );
312
313                let value = "";
314
315                if (p.curier_slug === "sameday" && p.curier_type === "locker") {
316                    value = `${p.curier_routing_location}|||${p.curier_address_zip}|||${p.curier_address_locality}|||${p.curier_external_id}`;
317                } else if (p.curier_slug === "dpd" && p.curier_type === "locker") {
318                    const dpdId = String(
319                        p.curier_external_id || p.pickup_point_id || p.id || ""
320                    );
321                    const routing =
322                        String(p.curier_routing_location || "").trim() || dpdId;
323                    value = `${routing}|||${p.curier_address_zip || ""}|||${
324                        p.curier_address_locality || ""
325                    }|||${dpdId}`;
326                } else {
327                    value = `${p.curier_routing_location}|||${p.curier_address_zip}`;
328                }
329
330                pickupInput.value = value;
331                if (countyLocalityInput) {
332                    countyLocalityInput.value = `${p.curier_address_county || ""}|||${
333                        p.curier_address_locality || ""
334                    }`;
335                }
336                const lockerFullAddress = `
337                      ${p.curier_name || ""}
338                      ${p.curier_address_street || ""} Nr. ${p.curier_address_street_no || ""},
339                      ${p.curier_address_locality || ""}, ${p.curier_address_county || ""}
340`
341                    .replace(/\s+/g, " ")
342                    .trim();
343
344                document.getElementById("lockerAddressHidden").value =
345                    lockerFullAddress;
346
347                const finalSlug = p.curier_slug ? p.curier_slug : currentCourierSlug;
348                const finalType = p.curier_type ? p.curier_type : currentCourierType;
349
350                const selectedCourier = window.couriers.find(
351                    (c) => c.slug === finalSlug
352                );
353
354                let selectedService = null;
355                if (selectedCourier) {
356                    selectedService = selectedCourier.services.find(
357                        (s) =>
358                            (finalSlug === "sameday" && String(s.service_id) === "15") ||
359                            (finalSlug === "fancourier" &&
360                                ["27", "4", "20"].includes(String(s.service_id))) ||
361                            (finalSlug === "dpd" && String(s.service_id) !== "2505")
362                    );
363
364                    if (
365                        !selectedService &&
366                        selectedCourier.services &&
367                        selectedCourier.services.length
368                    ) {
369                        selectedService = selectedCourier.services[0];
370                    }
371                }
372
373                if (!selectedService && p.curier_service_id) {
374                    selectedService = {
375                        id: p.curier_service_id,
376                        service_id: p.curier_service_id,
377                        name_code: p.curier_service_name_code || "",
378                        name: p.curier_service_name || "",
379                    };
380                }
381
382                const lockerInput = document.getElementById("shipping-locker-unic");
383
384                // console.log("LOCKER SELECTED", {
385                //     courierSlug: finalSlug,
386                //     serviceId: selectedService?.id || "",
387                //     serviceCode: selectedService?.service_id || "",
388                //     serviceNameCode: selectedService?.name_code || "",
389                //     courierType: finalType,
390                //     serviceName: `Ridicare personală ${selectedCourier?.name || ""}`,
391                // });
392
393                lockerInput.value = JSON.stringify({
394                    courierSlug: finalSlug,
395                    serviceId: selectedService?.id || "",
396                    serviceCode: selectedService?.service_id || "",
397                    serviceNameCode: selectedService?.name_code || "",
398                    courierType: finalType,
399                    serviceName: `Ridicare personală ${selectedCourier?.name || ""}`,
400                });
401
402                lockerInput.checked = true;
403                lockerInput.dispatchEvent(new Event("change", {bubbles: true}));
404                hasUserSelectedCourier = true;
405                togglePaymentMethods(true);
406
407                document.querySelector(".selected-pickup-point").innerHTML = `
408          <strong>${p.curier_name}</strong><br>
409          ${p.curier_address_street || ""} Nr. ${
410                    p.curier_address_street_no || ""
411                }
412          ${p.curier_address_locality}, ${p.curier_address_county}
413        `;
414
415                bootstrap.Modal.getInstance(lockerModal).hide();
416                updateLockerButtonText();
417                updateCourierPrices();
418            };
419        }
420    });
421
422    if (!p._marker) p._marker = marker;
423}
424
425document.getElementById("lockerSearch").addEventListener("input", function () {
426    const q = this.value.toLowerCase().trim();
427    lockerCluster.clearLayers();
428    const suggestions = document.getElementById("lockerSuggestions");
429    suggestions.innerHTML = "";
430
431    let matches = [];
432
433    if (q === "") {
434        matches = lockerPoints.filter(
435            (p) => p.curier_address_locality.toLowerCase() === "bucuresti"
436        );
437        if (matches.length) {
438            lockerMap.setView([44.4268, 26.1025], 13);
439        }
440    } else {
441        matches = lockerPoints.filter(
442            (p) =>
443                p.curier_name.toLowerCase().includes(q) ||
444                p.curier_address_locality.toLowerCase().includes(q) ||
445                `${p.curier_name} ${p.curier_address_street} ${p.curier_address_street_no} ${p.curier_address_locality}`
446                    .toLowerCase()
447                    .includes(q)
448        );
449    }
450
451    matches.forEach((p) => {
452        const marker = p._marker || createLockerMarker(p);
453        if (!marker) return;
454
455        lockerCluster.addLayer(marker);
456
457        const item = document.createElement("button");
458        item.type = "button";
459        item.className = "list-group-item list-group-item-action";
460        item.textContent = `${p.curier_name} - ${p.curier_address_locality}`;
461
462        item.addEventListener("click", () => {
463            lockerCluster.clearLayers();
464            const marker = p._marker || createLockerMarker(p);
465            if (!marker) return;
466            addPopupToMarker(marker, p);
467            p._marker = marker;
468            lockerCluster.addLayer(marker);
469
470            lockerMap.setView(
471                [parseFloat(p.curier_latitude), parseFloat(p.curier_longitude)],
472                19,
473                {animate: false}
474            );
475            marker.openPopup();
476
477            suggestions.innerHTML = "";
478            document.getElementById(
479                "lockerSearch"
480            ).value = `${p.curier_name} ${p.curier_address_locality}`;
481
482            const pickupInput = document.querySelector(".pickup-point");
483            const countyLocalityInput = document.querySelector(
484                ".pickup-county-locality"
485            );
486
487            let value = "";
488
489            if (p.curier_slug === "sameday" && p.curier_type === "locker") {
490                value = `${p.curier_routing_location}|||${p.curier_address_zip}|||${p.curier_address_locality}|||${p.curier_external_id}`;
491            } else if (p.curier_slug === "dpd" && p.curier_type === "locker") {
492                const dpdId = String(
493                    p.curier_external_id || p.pickup_point_id || p.id || ""
494                );
495                const routing = String(p.curier_routing_location || "").trim() || dpdId;
496                value = `${routing}|||${p.curier_address_zip || ""}|||${
497                    p.curier_address_locality || ""
498                }|||${dpdId}`;
499            } else {
500                value = `${p.curier_routing_location}|||${p.curier_address_zip}`;
501            }
502
503            pickupInput.value = value;
504            if (countyLocalityInput) {
505                countyLocalityInput.value = `${p.curier_address_county || ""}|||${
506                    p.curier_address_locality || ""
507                }`;
508            }
509
510            const lockerFullAddress = `
511  ${p.curier_name || ""}
512  ${p.curier_address_street || ""} Nr. ${p.curier_address_street_no || ""},
513  ${p.curier_address_locality || ""}, ${p.curier_address_county || ""}
514`
515                .replace(/\s+/g, " ")
516                .trim();
517
518            document.getElementById("lockerAddressHidden").value = lockerFullAddress;
519
520            const finalSlug = p.curier_slug;
521            const finalType = p.curier_type;
522
523            const selectedCourier = window.couriers.find((c) => c.slug === finalSlug);
524
525            let selectedService = null;
526            if (selectedCourier) {
527                selectedService = selectedCourier.services.find(
528                    (s) =>
529                        (finalSlug === "sameday" && String(s.service_id) === "15") ||
530                        (finalSlug === "fancourier" &&
531                            ["27", "4", "20"].includes(String(s.service_id))) ||
532                        (finalSlug === "dpd" && String(s.service_id) !== "2505")
533                );
534
535                if (!selectedService && selectedCourier.services?.length) {
536                    selectedService = selectedCourier.services[0];
537                }
538            }
539
540            if (!selectedService && p.curier_service_id) {
541                selectedService = {
542                    id: p.curier_service_id,
543                    service_id: p.curier_service_id,
544                    name_code: p.curier_service_name_code || "",
545                    name: p.curier_service_name || "",
546                };
547            }
548
549            const lockerInput = document.getElementById("shipping-locker-unic");
550
551            // console.log("LOCKER SELECTED", {
552            //     courierSlug: selectedCourier?.slug,
553            //     serviceId: selectedService?.id || "",
554            //     serviceCode: selectedService?.service_id || "",
555            //     serviceNameCode: selectedService?.name_code || "",
556            //     courierType: finalType,
557            //     serviceName: `Ridicare personală ${selectedCourier?.name || ""}`,
558            // });
559
560            lockerInput.value = JSON.stringify({
561                courierSlug: selectedCourier?.slug,
562                serviceId: selectedService?.id || "",
563                serviceCode: selectedService?.service_id || "",
564                serviceNameCode: selectedService?.name_code || "",
565                courierType: finalType,
566                serviceName: `Ridicare personală ${selectedCourier?.name || ""}`,
567            });
568
569            lockerInput.checked = true;
570            lockerInput.dispatchEvent(new Event("change", {bubbles: true}));
571            hasUserSelectedCourier = true;
572
573            document.querySelector(".selected-pickup-point").innerHTML = `
574    <strong>${p.curier_name}</strong><br>
575    ${p.curier_address_street || ""} Nr. ${p.curier_address_street_no || ""}<br>
576    ${p.curier_address_locality}, ${p.curier_address_county}
577  `;
578
579            updateLockerButtonText();
580            updateCourierPrices();
581            bootstrap.Modal.getInstance(lockerModal).hide();
582            togglePaymentMethods(true);
583        });
584
585        suggestions.appendChild(item);
586    });
587
588    if (matches.length === 1 && q.length > 5) {
589        const p = matches[0];
590        const marker = p._marker || createLockerMarker(p);
591        lockerCluster.clearLayers();
592        if (!marker) return;
593        addPopupToMarker(marker, p);
594        p._marker = marker;
595        lockerCluster.addLayer(marker);
596
597        lockerMap.setView(
598            [parseFloat(p.curier_latitude), parseFloat(p.curier_longitude)],
599            19,
600            {animate: false}
601        );
602        marker.openPopup();
603
604        suggestions.innerHTML = "";
605    }
606});
607
608document.getElementById("lockerSearch").addEventListener("paste", function (e) {
609    const input = this;
610    setTimeout(() => {
611        const event = new Event("input", {bubbles: true});
612        input.dispatchEvent(event);
613    }, 50);
614});
615
616function createLockerMarker(p) {
617    const slug = p.curier_slug || currentCourierSlug;
618    const type = p.curier_type || currentCourierType;
619
620    if (!p.curier_latitude || !p.curier_longitude) return null;
621
622    let icon = null;
623
624    if (slug === "fancourier" && type === "fanbox") {
625        icon = fanboxIcon;
626    } else if (slug === "sameday" && type === "locker") {
627        icon = easyboxIcon;
628    } else if (slug === "dpd" && type === "locker") {
629        icon = dpdLockerIcon;
630    } else {
631        return null;
632    }
633
634    const marker = L.marker(
635        [parseFloat(p.curier_latitude), parseFloat(p.curier_longitude)],
636        {icon: icon}
637    );
638
639    return marker;
640}
641
642document.querySelectorAll(".courier-tab").forEach((btn) => {
643    btn.addEventListener("click", async () => {
644        document
645            .querySelectorAll(".courier-tab")
646            .forEach((b) => b.classList.remove("active"));
647        btn.classList.add("active");
648
649        currentCourierSlug = btn.dataset.slug;
650        currentCourierType = btn.dataset.type;
651
652        lockerCluster.clearLayers();
653        resetLockerMapView();
654        lockerMap.eachLayer((layer) => {
655            if (layer instanceof L.Marker && !(layer instanceof L.MarkerCluster)) {
656                lockerMap.removeLayer(layer);
657            }
658        });
659
660        lockerPoints.forEach((p) => {
661            p._marker = null;
662        });
663
664        const response = await fetch(
665            `/api-couriers/v2/api-get-courier-pickup-points.php?slug=${currentCourierSlug}&type=${currentCourierType}`
666        );
667        const data = await response.json();
668
669        lockerPoints = (data.pickup_points || []).map((p) => {
670            p.curier_slug = currentCourierSlug;
671            p.curier_type = currentCourierType;
672            p._marker = null;
673            return p;
674        });
675
676        lockerPoints.forEach((p) => {
677            const marker = createLockerMarker(p);
678            if (!marker) return;
679            addPopupToMarker(marker, p);
680            p._marker = marker;
681            lockerCluster.addLayer(marker);
682        });
683
684        document.getElementById("lockerSearch").value = "";
685        document.getElementById("lockerSuggestions").innerHTML = "";
686    });
687});
688
689function capitalizeFirst(str) {
690    str = str.trim().replace(/^_+/, "");
691    return str.charAt(0).toUpperCase() + str.slice(1);
692}
693
694let currentCourierSlug = "";
695let currentCourierType = "";
696let hasUserSelectedCourier = false;
697
698let globalLowestPrice = Infinity;
699let globalCheapestServiceId = null;
700let globalCheapestCourierSlug = null;
701
702let couriers = [];
703currentCourierSlug = "sameday";
704currentCourierType = "locker";
705
706function moneyToNumber(s) {
707    s = String(s || "")
708        .trim()
709        .replace(/[^\d.,-]/g, "");
710    const hasC = s.includes(","),
711        hasD = s.includes(".");
712    if (hasC && hasD) {
713        const dec = s.lastIndexOf(",") > s.lastIndexOf(".") ? "," : ".";
714        const thou = dec === "," ? "." : ",";
715        return parseFloat(s.split(thou).join("").replace(dec, ".")) || 0;
716    }
717    if (hasC) return parseFloat(s.replace(/\./g, "").replace(",", ".")) || 0;
718    return parseFloat(s.replace(/,/g, "")) || 0;
719}
720
721function getOrderAmountNoShipping() {
722    const finalTxt =
723        (
724            document.getElementById("total-final") ||
725            document.querySelector(".cart-summary-total")
726        )?.textContent || "0";
727
728    const shipEl =
729        document.getElementById("total-shipping-tax") ||
730        document.getElementById("total-transport") ||
731        document.querySelector('.cart-summary-item-value[id*="shipping"]') ||
732        document.querySelector(".cart-summary-shipping");
733
734    const shipTxt = shipEl?.textContent || "0";
735
736    const subtotal = Math.max(
737        moneyToNumber(finalTxt) - moneyToNumber(shipTxt),
738        0
739    );
740    return subtotal;
741}
742
743async function loadCouriers() {
744    const container = document.querySelector(".shipping-methods");
745    if (!container) return;
746    container.innerHTML = "";
747    const isDifferent = document.querySelector("#isDifferentShipping")?.checked;
748
749    let county = "";
750    let locality = "";
751
752    if (isDifferent) {
753        county = document.querySelector("#countyInputShipping")?.value || "";
754        locality = document.querySelector("#localityInputShipping")?.value || "";
755    } else {
756        county = document.querySelector("#countyInput")?.value || "";
757        locality = document.querySelector("#localityInput")?.value || "";
758    }
759    const payload = {
760        weight: (() => {
761            const inputWeight = document.getElementById("cart-total-weight");
762            return inputWeight ? parseFloat(inputWeight.value) || 1 : 1;
763        })(),
764        order_amount: getOrderAmountNoShipping(),
765        payment_method: (() => {
766            const selectedPayment = document.querySelector(
767                'input[name="payment-method"]:checked'
768            );
769            return selectedPayment ? selectedPayment.value : "1";
770        })(),
771        county,
772        locality,
773    };
774
775    const response = await fetch("/api-couriers/v2/api-get-couriers.php", {
776        method: "POST",
777        headers: {"Content-Type": "application/json"},
778        body: JSON.stringify(payload),
779    });
780
781    const data = await response.json();
782    const couriers = data.couriers;
783    window.couriers = couriers;
784
785    let cheapestCourier = null;
786    let cheapestService = null;
787    let lowestPrice = Infinity;
788
789    couriers.forEach((courier) => {
790        courier.services.forEach((service) => {
791            const isHome =
792                (courier.slug === "fancourier" && service.service_id == 1) ||
793                (courier.slug === "sameday" && service.service_id == 7) ||
794                courier.slug === "bookurier" ||
795                (courier.slug === "dpd" && service.service_id == 2505);
796
797            let price = parseFloat(service.estimated_price ?? service.price);
798            if (isNaN(price)) price = Infinity;
799
800            if (isHome && price < lowestPrice) {
801                lowestPrice = price;
802                cheapestCourier = courier;
803                cheapestService = service;
804            }
805        });
806    });
807
808    if (!cheapestCourier || !cheapestService) {
809        cheapestCourier =
810            couriers.find((c) => c.slug === "bookurier") ||
811            couriers.find((c) => c.slug === "fancourier") ||
812            couriers.find((c) => c.slug === "sameday") ||
813            couriers[0];
814
815        if (cheapestCourier) {
816            cheapestService =
817                cheapestCourier.services.find(
818                    (s) =>
819                        (cheapestCourier.slug === "fancourier" && s.service_id == 1) ||
820                        (cheapestCourier.slug === "sameday" && s.service_id == 7) ||
821                        cheapestCourier.slug === "bookurier"
822                ) || cheapestCourier.services[0];
823        }
824    }
825
826    if (cheapestCourier && cheapestService) {
827        const shippingId = `shipping-${cheapestCourier.slug}-${cheapestService.service_id}`;
828        const wrap = document.createElement("div");
829        wrap.className = "shipping-method-wrap mb-2";
830
831        const inputDiv = document.createElement("div");
832        inputDiv.className = "form-check";
833
834        const input = document.createElement("input");
835        input.className = "form-check-input";
836        input.type = "radio";
837        input.id = shippingId;
838        input.name = "shipping-method";
839        input.value = JSON.stringify({
840            courierSlug: cheapestCourier.slug,
841            serviceId: cheapestService.id,
842            serviceCode: cheapestService.service_id,
843            serviceNameCode: cheapestService.name_code,
844            serviceName: "La domiciliu prin curier",
845        });
846        input.checked = true;
847
848        const label = document.createElement("label");
849        label.className = "form-check-label";
850        label.setAttribute("for", shippingId);
851        const priceLabel =
852            lowestPrice < Infinity && lowestPrice > 0
853                ? `${lowestPrice.toFixed(2)} lei`
854                : "";
855        label.innerHTML = `Livrare la domiciliu prin curier ${priceLabel}`;
856
857        inputDiv.appendChild(input);
858        inputDiv.appendChild(label);
859        wrap.appendChild(inputDiv);
860        container.appendChild(wrap);
861
862        input.addEventListener("change", () => {
863            document.querySelectorAll(".payment-method-wrap").forEach((method) => {
864                method.classList.remove("d-none");
865            });
866        });
867    }
868
869    const lockerWrap = document.createElement("div");
870    lockerWrap.className = "shipping-method-wrap mb-2";
871
872    const lockerInputDiv = document.createElement("div");
873    lockerInputDiv.className = "form-check";
874
875    const lockerInput = document.createElement("input");
876    lockerInput.className = "form-check-input";
877    lockerInput.type = "radio";
878    lockerInput.id = "shipping-locker-unic";
879    lockerInput.name = "shipping-method";
880    lockerInput.value = "";
881
882    const lockerLabel = document.createElement("label");
883    lockerLabel.className = "form-check-label";
884    lockerLabel.setAttribute("for", "shipping-locker-unic");
885    lockerLabel.innerHTML = `
886  Ridicare personală din locker 
887  <span class="selected-pickup-point"></span><br>
888  <input type="hidden" name="pickup-point" class="pickup-point" value="">
889  <input type="hidden" class="pickup-county-locality" name="pickup-county-locality" value="">
890  <input type="hidden" name="locker_address" id="lockerAddressHidden" value="">
891  <button type="button" id="open-locker-modal" class="btn btn-link p-0">
892    Click și alege locker preferat
893  </button>
894`;
895    lockerInputDiv.appendChild(lockerInput);
896    lockerInputDiv.appendChild(lockerLabel);
897    lockerWrap.appendChild(lockerInputDiv);
898    container.appendChild(lockerWrap);
899
900    document.getElementById("open-locker-modal").addEventListener("click", () => {
901        const selectedCourier = window.couriers.find(
902            (c) => c.slug === currentCourierSlug
903        );
904        if (!selectedCourier) {
905            alert("Nu există locker disponibil!");
906            return;
907        }
908
909        /*
910        const selectedService =
911            selectedCourier.services && selectedCourier.services[0]
912                ? selectedCourier.services[0]
913                : null;
914        */
915
916        let selectedService = null;
917
918        if (selectedCourier?.services?.length) {
919            selectedService = selectedCourier.services.find(
920                (s) =>
921                    (selectedCourier.slug === "sameday" && String(s.service_id) === "15") ||
922                    (selectedCourier.slug === "fancourier" &&
923                        ["27", "4", "20"].includes(String(s.service_id))) ||
924                    (selectedCourier.slug === "dpd" &&
925                        String(s.service_id) !== "2505")
926            );
927
928            if (!selectedService) {
929                selectedService = selectedCourier.services[0];
930            }
931        }
932
933        if (!selectedService) {
934            alert("Nu există servicii disponibile pentru acest curier!");
935            return;
936        }
937
938        const lockerTypeFromTab =
939            document.querySelector(".courier-tab.active")?.dataset?.type || "";
940        const resolvedLockerType =
941            lockerTypeFromTab ||
942            (selectedCourier.slug === "fancourier" ? "fanbox" : "locker");
943
944        currentCourierSlug = selectedCourier.slug;
945        currentCourierType = resolvedLockerType;
946
947        const lockerInput = document.getElementById("shipping-locker-unic");
948
949        // console.log("LOCKER SELECTED", {
950        //     courierSlug: selectedCourier.slug,
951        //     serviceId: selectedService.id,
952        //     serviceCode: selectedService.service_id,
953        //     serviceNameCode: selectedService.name_code,
954        //     courierType: currentCourierType,
955        //     serviceName: `Ridicare personală ${selectedCourier.name}`,
956        // });
957
958        lockerInput.value = JSON.stringify({
959            courierSlug: selectedCourier.slug,
960            serviceId: selectedService.id,
961            serviceCode: selectedService.service_id,
962            serviceNameCode: selectedService.name_code,
963            courierType: currentCourierType,
964            serviceName: `Ridicare personală ${selectedCourier.name}`,
965        });
966
967        lockerInput.checked = true;
968        lockerInput.dispatchEvent(new Event("change"));
969
970        const myModal = new bootstrap.Modal(
971            document.getElementById("lockerMapModal")
972        );
973        myModal.show();
974    });
975
976    updateCourierPrices();
977    togglePaymentMethods(false);
978}
979
980function togglePaymentMethods(isLocker) {
981    const ramburs = document.querySelector(".method-ramburs");
982    const card = document.querySelector(".method-card");
983
984    if (!ramburs || !card) return;
985
986    if (isLocker) {
987        ramburs.classList.add("d-none");
988        const netopia = document.querySelector("#payment-netopia-card");
989        if (netopia) {
990            netopia.checked = true;
991            netopia.dispatchEvent(new Event("change"));
992        }
993    } else {
994        ramburs.classList.remove("d-none");
995    }
996}
997
998function updateLockerButtonText() {
999    const pickupInput = document.querySelector(".pickup-point");
1000    const openBtn = document.getElementById("open-locker-modal");
1001    if (pickupInput && pickupInput.value.trim()) {
1002        openBtn.textContent = "Schimbă locker";
1003    } else {
1004        openBtn.textContent = "Click și alege locker preferat";
1005    }
1006}
1007
1008async function updateCourierPrices() {
1009    globalLowestPrice = Infinity;
1010    globalCheapestCourierSlug = null;
1011    globalCheapestServiceId = null;
1012
1013    document.querySelectorAll(".best-price-badge").forEach((b) => b.remove());
1014
1015    const allInputs = Array.from(
1016        document.querySelectorAll('input[name="shipping-method"]')
1017    );
1018    if (!allInputs.length) return;
1019
1020    const paymentMethod = (() => {
1021        const selected = document.querySelector(
1022            'input[name="payment-method"]:checked'
1023        );
1024        return selected ? selected.value : "1";
1025    })();
1026    const orderAmount = getOrderAmountNoShipping();
1027
1028    for (const input of allInputs) {
1029        if (!input.value) continue;
1030
1031
1032        const selected = JSON.parse(input.value);
1033        const selectedServiceCode = String(selected.serviceCode);
1034        const courierSlug = selected.courierSlug;
1035
1036        if (!["fancourier", "sameday", "bookurier", "dpd"].includes(courierSlug))
1037            continue;
1038
1039        const inputContainer = input.closest(".shipping-method-wrap");
1040
1041        let county = "";
1042        let locality = "";
1043        let pickupPoint = "";
1044
1045        const isLockerRadio = input.id === "shipping-locker-unic";
1046
1047        const isHomeDelivery =
1048            !isLockerRadio &&
1049            ((courierSlug === "fancourier" && selectedServiceCode === "1") ||
1050                (courierSlug === "sameday" && selectedServiceCode === "7") ||
1051                courierSlug === "bookurier" ||
1052                (courierSlug === "dpd" && selectedServiceCode === "2505"));
1053
1054        if (isHomeDelivery) {
1055            const isDifferentShipping = document.querySelector(
1056                "#isDifferentShipping"
1057            )?.checked;
1058            if (isDifferentShipping) {
1059                county = document.querySelector("#countyInputShipping")?.value || "";
1060                locality =
1061                    document.querySelector("#localityInputShipping")?.value || "";
1062            } else {
1063                county = document.querySelector("#countyInput")?.value || "";
1064                locality = document.querySelector("#localityInput")?.value || "";
1065                if (county.toLowerCase() === "bucuresti") {
1066                    const sectorSelect = document.querySelector("#sectorInput");
1067                    if (sectorSelect && sectorSelect.value) {
1068                        locality = "Sector " + sectorSelect.value;
1069                    } else {
1070                        continue;
1071                    }
1072                }
1073            }
1074        } else {
1075            pickupPoint = document.querySelector(".pickup-point")?.value || "";
1076
1077            const countyLocality =
1078                document.querySelector(".pickup-county-locality")?.value || "";
1079            if (countyLocality.includes("|||")) {
1080                const parts = countyLocality.split("|||");
1081                if (parts.length === 2) {
1082                    county = parts[0].trim();
1083                    locality = parts[1].trim();
1084                }
1085            }
1086
1087            if (!county) county = "N/A";
1088            if (!locality && pickupPoint.includes("|||")) {
1089                const parts = pickupPoint.split("|||");
1090                if (parts.length >= 3) {
1091                    locality = parts[2].trim();
1092                }
1093            }
1094        }
1095
1096        if (isHomeDelivery && (county === "" || locality === "")) continue;
1097
1098        const isLockerShipment =
1099            input.id === "shipping-locker-unic" || selected.courierType === "locker";
1100
1101        if (isLockerShipment && pickupPoint === "") continue;
1102
1103        const finalWeight = (() => {
1104            const inputWeight = document.getElementById("cart-total-weight");
1105            return inputWeight ? parseFloat(inputWeight.value) || 1 : 1;
1106        })();
1107
1108        const payload = {
1109            courierSlug,
1110            serviceCode: selectedServiceCode,
1111            county,
1112            locality,
1113            weight: finalWeight,
1114            order_amount: orderAmount,
1115            payment_method: paymentMethod,
1116            is_locker: Number(!isHomeDelivery)
1117        };
1118
1119        if (["27", "4", "20"].includes(selectedServiceCode)) {
1120            payload.pickup_county = county;
1121            payload.pickup_locality = locality;
1122            if (pickupPoint) payload.pickup_point = pickupPoint.split("|||")[0];
1123        }
1124
1125        if (selectedServiceCode === "15") {
1126            const parts = pickupPoint.trim().split("|||");
1127            const lockerId = parts.at(-1)?.trim();
1128            if (!lockerId || !/^[a-zA-Z0-9]+$/.test(lockerId)) {
1129                console.warn("Locker ID lipsă sau invalid:", pickupPoint);
1130                input.setAttribute("data-price", "0");
1131                continue;
1132            }
1133            payload.pickup_point = lockerId;
1134        }
1135
1136        try {
1137            const response = await fetch(
1138                "/api-couriers/v2/api-get-courier-price.php",
1139                {
1140                    method: "POST",
1141                    headers: {"Content-Type": "application/json"},
1142                    body: JSON.stringify(payload),
1143                }
1144            );
1145
1146            if (!response.ok) continue;
1147
1148            const data = await response.json();
1149            const price = parseFloat(data.price);
1150
1151            input.setAttribute("data-estimated-price", data.estimated_price ?? "");
1152            input.setAttribute("data-price", !isNaN(price) ? price.toFixed(2) : "0");
1153
1154            const isLockerRadio = input.id === "shipping-locker-unic";
1155            const label = isLockerRadio
1156                ? document.querySelector('label[for="shipping-locker-unic"]')
1157                : document.querySelector(`label[for="shipping-${courierSlug}-${selectedServiceCode}"]`);
1158
1159            input.setAttribute("data-estimated-price", data.estimated_price ?? "");
1160
1161            if (input.checked) {
1162                const estimatedPriceInput = document.getElementById(
1163                    "estimatedPriceInput"
1164                );
1165                if (estimatedPriceInput) {
1166                    estimatedPriceInput.value = data.estimated_price ?? "";
1167                }
1168            }
1169
1170            if (label) {
1171                label
1172                    .querySelectorAll(".free-shipping-badge")
1173                    .forEach((b) => b.remove());
1174
1175                const isLocker = input.id === "shipping-locker-unic";
1176
1177                if (!isNaN(price)) {
1178                    if (isLocker) {
1179                        const pickupPointSpan = label.querySelector(
1180                            ".selected-pickup-point"
1181                        );
1182                        let badgeSpan = label.querySelector(".locker-price-badge");
1183                        if (pickupPointSpan) {
1184                            if (badgeSpan) {
1185                                badgeSpan.textContent = ` (${price.toFixed(2)} lei)`;
1186                            } else {
1187                                pickupPointSpan.insertAdjacentHTML(
1188                                    "afterend",
1189                                    ` <span class="locker-price-badge">(${price.toFixed(
1190                                        2
1191                                    )} lei)</span>`
1192                                );
1193                            }
1194                        }
1195                        set_shipping_tax(price.toFixed(2));
1196                    } else {
1197                        label.innerHTML = `${selected.serviceName} (${price.toFixed(
1198                            2
1199                        )} lei)`;
1200                    }
1201
1202                    if (price < globalLowestPrice) {
1203                        globalLowestPrice = price;
1204                        globalCheapestCourierSlug = courierSlug;
1205                        globalCheapestServiceId = selectedServiceCode;
1206                    }
1207                } else {
1208                    if (!isLocker) {
1209                        label.innerHTML = `${selected.serviceName}`;
1210                    }
1211                }
1212
1213                if (data.is_free_shipping || price === 0) {
1214                    const freeBadge = document.createElement("span");
1215                    freeBadge.className = "badge bg-success ms-2 free-shipping-badge";
1216                    freeBadge.setAttribute(
1217                        "title",
1218                        data.free_delivery_threshold
1219                            ? `Transport gratuit peste ${parseFloat(
1220                                data.free_delivery_threshold
1221                            ).toFixed(2)} lei`
1222                            : "Transport gratuit activat"
1223                    );
1224                    freeBadge.textContent = "Transport gratuit";
1225                    label.appendChild(freeBadge);
1226                    new bootstrap.Tooltip(freeBadge);
1227                }
1228            }
1229        } catch (err) {
1230            console.warn("Eroare la estimare preț:", err);
1231        }
1232    }
1233
1234    if (
1235        !hasUserSelectedCourier &&
1236        globalCheapestCourierSlug &&
1237        globalCheapestServiceId
1238    ) {
1239        const cheapestInput = document.querySelector(
1240            `#shipping-${globalCheapestCourierSlug}-${globalCheapestServiceId}`
1241        );
1242        if (cheapestInput && !cheapestInput.checked) {
1243            cheapestInput.checked = true;
1244            cheapestInput.dispatchEvent(new Event("change"));
1245        }
1246        const isLocker = ["15", "27", "4", "20"].includes(
1247            String(globalCheapestServiceId)
1248        );
1249        if (!isLocker) {
1250            const newPrice = cheapestInput?.dataset.price || "0";
1251            set_shipping_tax(newPrice);
1252        }
1253    }
1254}
1255
1256document.addEventListener("DOMContentLoaded", async () => {
1257    await loadCouriers();
1258    hasUserSelectedCourier = false;
1259    await updateCourierPrices();
1260
1261    document
1262        .querySelector("#countyInput")
1263        ?.addEventListener("change", updateCourierPrices);
1264
1265    document
1266        .querySelector("#localityInput")
1267        ?.addEventListener("change", async function () {
1268            await updateCourierPrices();
1269            const selectedInput = document.querySelector(
1270                'input[name="shipping-method"]:checked'
1271            );
1272            if (selectedInput && selectedInput.dataset.price) {
1273                set_shipping_tax(selectedInput.dataset.price);
1274            }
1275        });
1276
1277    document
1278        .querySelector("#countyInputShipping")
1279        ?.addEventListener("change", updateCourierPrices);
1280
1281    document
1282        .querySelector("#localityInputShipping")
1283        ?.addEventListener("change", async function () {
1284            await updateCourierPrices();
1285            const selectedInput = document.querySelector(
1286                'input[name="shipping-method"]:checked'
1287            );
1288            if (selectedInput && selectedInput.dataset.price) {
1289                set_shipping_tax(selectedInput.dataset.price);
1290            }
1291        });
1292
1293    document
1294        .querySelector("#isDifferentShipping")
1295        ?.addEventListener("change", updateCourierPrices);
1296});
1297
1298function populateCountySelect(selectElement) {
1299    if (!window.COUNTIES || !Array.isArray(window.COUNTIES)) {
1300        return;
1301    }
1302
1303    window.COUNTIES.forEach(({name, nice_name}) => {
1304        const opt = document.createElement("option");
1305        opt.value = nice_name;
1306        opt.textContent = name;
1307        selectElement.appendChild(opt);
1308    });
1309}
1310
1311const requiredFieldsByMethod = {
1312    fancourier: {
1313        4: [".county-sediu", ".locality-sediu"],
1314        20: [".county-sediu", ".locality-sediu"],
1315        27: [".pickup-county", ".pickup-locality", ".pickup-point"],
1316    },
1317    sameday: {
1318        15: [".pickup-county", ".pickup-locality", ".pickup-point"],
1319    },
1320};
1321
1322function set_shipping_tax(shippingPrice) {
1323    $.ajax({
1324        method: "POST",
1325        url: "/",
1326        data: {
1327            action: "set-shipping-tax-courier",
1328            shipping_price: shippingPrice,
1329        },
1330        success: function (response) {
1331            if (response.success) {
1332                if (response.result) {
1333                    $.each(response.result, function (key, value) {
1334                        const htmlEl = key.replaceAll("_", "-");
1335                        if (key === "total_discounts") {
1336                            toggle_reducere_box(htmlEl, value);
1337                        } else {
1338                            if (key === "total_final") {
1339                                $("#" + htmlEl).html(
1340                                    response.result.total_products_no_discounts + " lei"
1341                                );
1342                            } else {
1343                                $("#" + htmlEl).html(value + " lei");
1344                            }
1345                        }
1346                    });
1347                }
1348            }
1349        },
1350        error: function (xhr) {
1351            console.error(
1352                "Eroare AJAX set_shipping_tax:",
1353                xhr.status,
1354                xhr.responseText
1355            );
1356        },
1357    });
1358}
1359
1360function resetShippingSelection() {
1361    const selected = document.querySelector(
1362        'input[name="shipping-method"]:checked'
1363    );
1364    if (selected) {
1365        selected.checked = false;
1366    }
1367
1368    document.querySelectorAll('label[for^="shipping-"]').forEach((label) => {
1369        label.querySelectorAll(".badge, small").forEach((el) => el.remove());
1370
1371        const originalText = label.textContent.split("(")[0].trim();
1372        label.innerHTML = `${originalText}`;
1373    });
1374
1375    document
1376        .querySelectorAll('input[name="shipping-method"]')
1377        .forEach((input) => {
1378            input.removeAttribute("data-price");
1379        });
1380
1381    set_shipping_tax(0);
1382
1383    hasUserSelectedCourier = false;
1384}
1385
1386document
1387    .querySelector(".shipping-methods")
1388    ?.addEventListener("change", function (event) {
1389        const target = event.target;
1390        if (target && target.matches('input[name="shipping-method"]')) {
1391            const selectedInput = target;
1392
1393            const isLocker = selectedInput.id === "shipping-locker-unic";
1394            togglePaymentMethods(isLocker);
1395
1396            const price = selectedInput.dataset.price || "0";
1397            set_shipping_tax(price);
1398
1399            const estimatedPrice = selectedInput.dataset.estimatedPrice || "";
1400            const estimatedPriceInput = document.getElementById(
1401                "estimatedPriceInput"
1402            );
1403            if (estimatedPriceInput) {
1404                estimatedPriceInput.value = estimatedPrice;
1405            }
1406        }
1407    });
1408
1409document.addEventListener("DOMContentLoaded", () => {
1410    document.querySelectorAll('input[name="payment-method"]').forEach((el) => {
1411        el.addEventListener("change", async () => {
1412            const isLockerSelected = document.querySelector(
1413                "#shipping-locker-unic"
1414            )?.checked;
1415
1416            if (!isLockerSelected) {
1417                await loadCouriers();
1418            }
1419
1420            await updateCourierPrices();
1421
1422            const selectedInput = document.querySelector(
1423                'input[name="shipping-method"]:checked'
1424            );
1425            if (selectedInput && selectedInput.dataset.price) {
1426                set_shipping_tax(selectedInput.dataset.price);
1427            }
1428        });
1429    });
1430
1431    document.addEventListener("change", function (e) {
1432        if (e.target && e.target.matches('input[name="shipping-method"]')) {
1433            hasUserSelectedCourier = true;
1434        }
1435    });
1436    document
1437        .querySelector("#sectorInput")
1438        ?.addEventListener("change", async () => {
1439            await updateCourierPrices();
1440            const selectedInput = document.querySelector(
1441                'input[name="shipping-method"]:checked'
1442            );
1443            if (selectedInput && selectedInput.dataset.price) {
1444                set_shipping_tax(selectedInput.dataset.price);
1445            }
1446        });
1447
1448    document
1449        .querySelector("#countyInput")
1450        ?.addEventListener("change", async () => {
1451            await loadCouriers();
1452            hasUserSelectedCourier = false;
1453            await updateCourierPrices();
1454        });
1455
1456    document
1457        .querySelector("#localityInput")
1458        ?.addEventListener("change", async () => {
1459            await loadCouriers();
1460            hasUserSelectedCourier = false;
1461            await updateCourierPrices();
1462        });
1463
1464    document
1465        .querySelector("#countyInputShipping")
1466        ?.addEventListener("change", async () => {
1467            await loadCouriers();
1468            hasUserSelectedCourier = false;
1469            await updateCourierPrices();
1470        });
1471
1472    document
1473        .querySelector("#localityInputShipping")
1474        ?.addEventListener("change", async () => {
1475            await loadCouriers();
1476            hasUserSelectedCourier = false;
1477            await updateCourierPrices();
1478        });
1479
1480    document
1481        .querySelector("#isDifferentShipping")
1482        ?.addEventListener("change", async () => {
1483            await loadCouriers();
1484            hasUserSelectedCourier = false;
1485            await updateCourierPrices();
1486        });
1487
1488    document
1489        .querySelector("#localityInputShipping")
1490        ?.addEventListener("blur", function () {
1491            this.dispatchEvent(new Event("change"));
1492        });
1493});

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.