Files
cdnPRO/modoo-pl/test.js
Jacek Pyziak 0f936196c9 Add projector functionality with price formatting and availability checks
- Implemented _formatPrice function for consistent price formatting.
- Added projectorEndStartCallback to handle size selection and price updates.
- Integrated availability notifications and user interaction for product sizes.
- Created CountdownTimer class for promotional countdowns.
- Developed StationaryPanel class for managing pickup point searches and geolocation.
- Included error handling for API requests and user input validation.
- Enhanced user experience with tooltips and dynamic content updates.
2025-10-06 23:14:16 +02:00

981 lines
39 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//zewnętrzna funkcja do formatowania cen
function _formatPrice(obj) {
return format_price(obj.price, {
mask: app_shop.vars.currency_format,
currency: obj.currency, //.replace(/\s+/g, ''),
currency_space: app_shop.vars.currency_space,
currency_before_price: app_shop.vars.currency_before_value
})
}
function projectorEndStartCallback() {
//powiadomienie o dostepnosci zmiana roziaru
$("#avability_product_size strong").text(projectorObj.currentSizeObj.description);
//przypisanie raty
cena_raty = projectorObj.currentSizeObj.price.value * projectorObj.configObj.valueOfNumberInput;
if (client_login) {
$('<span class="show_tip css_tip css_tip_small"><i class="icon-question"></i></span>').attr('title', txt_toltip_2a.replace('[xxx]', client_points)).appendTo('#projector_price_points');
} else {
$('<span class="show_tip css_tip css_tip_small"><i class="icon-question"></i></span>').attr('title', txt_toltip_2).appendTo('#projector_price_points');
}
$('<span class="show_tip css_tip css_tip_small"><i class="icon-question"></i></span>').attr('title', txt_toltip_3).appendTo('#projector_points_recive_points');
if (projectorObj.txt['size_select_functionality'] && projectorObj.txt['size_select_functionality'] != '0') {
app_shop.fn.fashionAvailability();
}
app_shop.fn.tommorowAvailability();
if (product_data.sizes && (product_data.sizes.uniw || product_data.sizes.onesize)) {
$('#projector_sizes_cont').hide();
}
if (projectorObj.currentSizeObj.phone_price != 'true' && projectorObj.currentSizeObj.bundle_price && projectorObj.currentSizeObj.bundle_price.amount_diff_gross > 0) {
$('#projector_price_yousave_bundle').show().html('<span class="projector_price_save_text">' + projectorObj.txt['oszczedzasz'] + '</span><span class="projector_price_save_percent">' + projectorObj.currentSizeObj.bundle_price.percent_diff + '</span><span class="projector_price_save_value">' + projectorObj.txt['taniej']);
} else if (projectorObj.currentSizeObj.phone_price != 'true' && yousaveTmp) {
$('#projector_price_yousave').show().html('<span class="projector_price_save_text">' + projectorObj.txt['oszczedzasz'] + '</span><span class="projector_price_save_percent">' + yousave_percentTmp + '</span><span class="projector_price_save_value">' + projectorObj.txt['taniej']);
} else {
$('#projector_price_yousave').hide();
$('#projector_price_yousave_bundle').hide();
}
if (projectorObj.currentSizeObj.product_type === "product_bundle") {
if (projectorObj.currentSizeObj.availability.status == 'disable') {
$('#projector_tell_availability').find('input').attr('disabled', false);
$('body').removeClass('alertek-disabled');
$.getJSON('/ajax/projector.php?action=get_product_observed', {
'product': $('#projector_product_hidden').val(),
'size': $('#projector_size_hidden').val(),
'email': $('#projector_tell_availability [name="email"]').val()
}, function (data) {
if (data.status == 'error') {
message = txt_62619_blad_pobrania;
Alertek.show_alert(message);
return false;
}
if (!data.sms_active) {
$('#sms_active_checkbox,#sms_active_group').remove();
}
if (data.client && data.client.phone) {
$('#sms_active_checkbox input').prop('checked', true);
$('#sms_active_checkbox,#sms_active_group').show()
$('#sms_active_group [name="phone"]').val(data.client.phone);
}
})
} else {
$('#projector_tell_availability').find('input').attr('disabled', true);
$('body').addClass('alertek-disabled');
}
}
// Aktualizacja rabatu ilościowego
const {price} = projectorObj.currentSizeObj;
if (typeof price !== 'undefined' && $('#projector_rebateNumber').length) {
const {rebateNumber} = price;
if ($('.rebate_number__item').length > 1) {
$('.rebate_number__item').each(function(index) {
$(this).find('.rebate_number__price').text(rebateNumber.items[index].price_formatted)
});
} else {
$('.rebate_number__price').text(rebateNumber.nextprice_formatted);
}
}
const {amount} = projectorObj.currentSizeObj;
$('.projector_delivery_info_container, #projector_status_description_wrapper, #projector_status_description_wrapper_shipping').removeClass('hidden');
if(typeof(amount) != "undefined" && amount < 4 && amount != -1){
$('#projector_status_description_wrapper, #projector_product_status_wrapper, #projector_status_description_wrapper_shipping').addClass('--less');
switch (amount){
case 0:
$('.projector_delivery_info_container').addClass('hidden');
$('#projector_status_description_wrapper_shipping').addClass('hidden');
break;
case 1:
$('#projector_status_description').html(projectorObj.txt['zostala'] + " " + "<strong>" + projectorObj.txt['sztuka1'] + " " + "</strong>" + projectorObj.txt['wRozmiarze']).addClass('only_one');
break;
case 2:
$('#projector_status_description').html(projectorObj.txt['zostaly'] + " " + "<strong>" + projectorObj.txt['sztuka2'] + "</strong>" + " " + projectorObj.txt['wRozmiarze']).addClass('only_one');
break;
case 3:
$('#projector_status_description').html(projectorObj.txt['zostaly'] + " " + "<strong>" + projectorObj.txt['sztuka2'] + "</strong>" + " " + projectorObj.txt['wRozmiarze']).addClass('only_one');
break;
}
}else{
$('#projector_status_description_wrapper, #projector_product_status_wrapper, #projector_status_description_wrapper_shipping').removeClass('--less');
}
if(projectorObj.currentSizeObj.type == "uniw"){
$('#projector_status_description_wrapper').addClass('hidden');
}
}
function projectorEndInitFunctionCallback() {
app_shop.fn.init_multi_vers();
//inicializacja toltipow
simple_tooltip("span.show_tip", "n59581_tooltip");
if (product_data.base_price && product_data.base_price.promotiontilldate) {
$('#projector_prices_wrapper').after('<div id="CDT" class="product_section CDT-uniw"></div>');
app_shop.vars.countDown = new CountdownTimer($('#CDT'), new Date(product_data.base_price.promotiontilldate + 'T23:59:59+01:00'));
app_shop.vars.countDown.countDown();
}
const selectedSizeFromURL = [...document.querySelectorAll('.select_button')].some(el=> el.className.includes('active'));
if($('#projector_sizes_cont .select_button').length>1 && !selectedSizeFromURL){
$('#projector_sizes_cont .select_button').first().click();
}
}
var pr_goToOpinion = function () {
$('#opinions_58676').click();
$('html,body').animate({
scrollTop: $('#component_projector_opinions').offset().top - 120
}, 'fast');
}
app_shop.run(function () {
var versionSub = $('#projector_form div.product_section.versions div.product_section_sub');
versionSub.find('.select_button').length > 8 ? versionSub.addClass('versions_scroll') : versionSub.removeClass('versions_scroll');
}, 1, '#projector_form', true);
$(document).on('click', '.mobile_toggle .mobile_text', function(e){
e.preventDefault();
$(this).parent().toggleClass('active');
})
$(document).on('click', '.question_section .mobile_text', function(){
$('.askforproduct').dialog({
wrappContent: true,
});
return false;
});
$(document).on('click', '.opinion_section .btn', function(){
$('.opinions_add_form').dialog({
wrappContent: true,
});
return false;
});
var projectorv3_disable_ajax = "1";
projectorObj = new projectorClass();
projectorObj.txt['sztuka1'] = "Została już tylko 1 sztuka w tym rozmiarze!"
projectorObj.txt['sztuka2'] = "Zostały już tylko 2 sztuki w tym rozmiarze!"
projectorObj.txt['sztuka3'] = "Zostały już tylko 3 sztuki w tym rozmiarze!"
projectorObj.txt['zostala'] = <iai:variable vid="Została już tylko"/>
projectorObj.txt['zostaly'] = <iai:variable vid="Zostały już tylko"/>
projectorObj.txt['sztuka1'] = <iai:variable vid="1 sztuka"/>
projectorObj.txt['sztuka2'] = <iai:variable vid="2 sztuki"/>
projectorObj.txt['sztuka3'] = <iai:variable vid="3 sztuki"/>
projectorObj.txt['wRozmiarze'] = <iai:variable vid="w tym rozmiarze!"/>
projectorObj.txt['additional_texts'] = ""
projectorObj.txt['za'] = " " + <iai:variable vid="za"/> + " "
projectorObj.txt['taniej'] = "% od pierwszej ceny"
projectorObj.txt['oszczedzasz'] = <iai:variable vid="Oszczędzasz"/> + " "
projectorObj.txt['wzestawie'] = "), " + <iai:variable vid="kupując w zestawie"/> + ". "
projectorObj.txt['niedostepny'] = <iai:variable vid="Produkt niedostępny"/>
projectorObj.txt['tylkotel'] = <iai:variable vid="Cena na telefon. Skontaktuj się ze sprzedawcą"/> + "."
projectorObj.txt['tylko_punkty'] = <iai:variable vid="Produkt dostępny tylko w programie lojalnościowym"/> + "."
projectorObj.txt['za_malo_punktow'] = <iai:variable vid="Nie masz wystarczającej ilości punktów"/>
projectorObj.txt['gratis'] = <iai:variable vid="Wysyłka gratis!"/>
projectorObj.txt['niemastanu'] = <iai:variable vid="Produkt niedostępny"/>
projectorObj.txt['status_24'] = <iai:variable vid="w ciągu 24h"/>
projectorObj.txt['status_natychmiast'] = <iai:variable vid="Natychmiast"/>
projectorObj.txt['day'] = " " + <iai:variable vid="dzień"/> + " "
projectorObj.txt['days'] = " " + <iai:variable vid="dni"/> + " "
projectorObj.txt['hour'] = " " + <iai:variable vid="godz"/> + "."
projectorObj.txt['hours'] = " " + <iai:variable vid="godz"/> + ". "
projectorObj.txt['min'] = " min "
projectorObj.txt['mins'] = " min. "
projectorObj.txt['proc'] = "%"
projectorObj.txt['wybrany_rozmiar'] = <iai:variable vid="Rozmiar"/> + ":"
projectorObj.txt['wysylka'] = ""
projectorObj.txt['wysylka_za'] = <iai:variable vid="w ciągu"/> + " "
projectorObj.txt['dostepny'] = ""
projectorObj.txt['dostepny_za'] = <iai:variable vid="za"/> + " "
projectorObj.txt['pkt'] = " " + <iai:variable vid="pkt"/> + "."
projectorObj.txt['status_amount_full'] = <iai:variable vid="większa ilość"/>
projectorObj.txt['status_amount_null'] = <iai:variable vid="brak w magazynie"/>
projectorObj.txt['forpointsonly'] = <iai:variable vid="Produkt możesz kupić za punkty"/> + "."
projectorObj.txt['disable_desc'] = <iai:variable vid="Skontaktuj się z nami"/> + "."
projectorObj.txt['choiceSize'] = <iai:variable vid="Wybierz rozmiar"/>
projectorObj.txt['maksymalnie'] = <iai:variable vid="Maksymalnie możesz dodać"/>
projectorObj.txt['minimalnie'] = <iai:variable vid="Minimalnie musisz zamówić"/> + " "
projectorObj.txt['brak_magazyn'] = <iai:variable vid="Brak na magazynie"/>
projectorObj.txt['koszt_od'] = <iai:variable vid="Koszt od"/> + " "
projectorObj.txt['wysylka_total_begin'] = "<br/>(" + <iai:variable vid="z tow. z koszyka"/> + " "
projectorObj.txt['wysylka_total_end'] = ")"
projectorObj.txt['nawias_end'] = "). "
projectorObj.txt['gratis_produkt'] = <iai:variable vid="Gratis!"/>
projectorObj.txt['virtual_inbasket'] = <iai:variable vid="Produkt znajduje się już w koszyku"/>
projectorObj.txt['infinity'] = ""
projectorObj.txt['ilosc_mm'] = "" + <iai:variable vid="Aktualnie w naszym magazynie mamy"/> + " <b>" + "%" + <iai:variable vid="d"/> + "</b>."
projectorObj.txt['ilosc_mo'] = "" + <iai:variable vid="Kolejne"/> + " <b>" + "%" + <iai:variable vid="d"/> + "</b> " + <iai:variable vid="możemy sprowadzić na zamówienie"/> + "."
projectorObj.txt['ilosc_mo_inf'] = <iai:variable vid="Dowolną ilość możemy sprawadzić na zamówienie"/> + "."
projectorObj.txt['size_select_functionality'] = "0"
projectorObj.txt['sizes_projector_functionality'] = "1"
projectorObj.txt['size_select_label'] = <iai:variable vid="Rozmiar"/>
projectorObj.txt['size_select_tell_availability'] = <iai:variable vid="Powiadom o dostępności"/>
projectorObj.txt['size_select_last_unit'] = <iai:variable vid="Ostatnia sztuka!"/>
projectorObj.txt['size_select_few_last_units'] = <iai:variable vid="Ostatnie sztuki!"/>
var Projector_txt_maksymalnie = <iai:variable vid="Maksymalnie możesz zamówić"/> + ": "
var Projector_txt_minimalnie = projectorObj.txt['minimalnie'];
var Projector_txt_brak_magazyn = <iai:variable vid="Brak na magazynie"/>
var Projector_txt_produkt_niedostepny = <iai:variable vid="Produkt niedostępny"/>
var Projector_txt_podajilosc = <iai:variable vid="Podaj ilość dla wybranego rozmiaru"/>
var Projector_txt_zalogujsie = <iai:variable vid="Zaloguj się"/>
var Projector_txt_closedialog = ""
var txt_raty_button1 = <iai:variable vid="Oblicz raty wybranego produktu"/>
var txt_raty_button2 = <iai:variable vid="Oblicz raty wraz z kwotą z koszyka"/> + " "
var txt_62619_cms_table = <iai:variable vid="Tabela rozmiarów"/>
var txt_toltip_1 = <iai:variable vid="Cena najtańszej z dostępnych form wysyłki z uwzględnieniem twojego koszyka. Pełną listę cen i kurierów otrzymasz podczas składania zamówienia"/> + "."
var txt_toltip_2 = <iai:variable vid="Program lojalnościowy dostępny jest tylko dla zalogowanych klientów"/> + "."
var txt_toltip_2a = <iai:variable vid="Możesz zamienić zgromadzone punkty lojalnościowe na ten produkt. Obecnie masz [xxx] punktów"/> + "."
var txt_toltip_3 = <iai:variable vid="Po opłaceniu zamówienia przyznamy ci taką ilość punktów lojalnościowych. Żeby zbierać punkty musisz być zarejestrowanym klientem"/> + "."
var txt_toltip_4 = ""
var prepaid = <iai:variable vid="Płatność przed wysyłką"/>
var dvp = <iai:variable vid="Płatność przy odbiorze"/>
var day_txt = " " + <iai:variable vid="dzień"/> + " "
var days_txt = " " + <iai:variable vid="dni"/> + " "
var hour_txt = " " + <iai:variable vid="godz"/> + ". "
var hours_txt = " " + <iai:variable vid="godz"/> + ". "
var min_txt = " min."
var txt_24h = <iai:variable vid="24h"/>
var txt_do_24h = <iai:variable vid="do 24h"/>
var delivery_txt = <iai:variable vid="Sam transport zajmie"/> + " "
var delivery_txt2 = <iai:variable vid="Przygotowanie do odbioru osobistego zajmie"/> + " "
var delivery_txt3 = <iai:variable vid="Forma dostawy dostępna od"/> + " "
var gratis_txt = <iai:variable vid="Gratis!"/>
app_shop.txt.txt_74629_1 = <iai:variable vid="Do końca promocji"/> + ": "
app_shop.txt.txt_74629_2 = <iai:variable vid="Wybierz inną opcję"/> + "."
app_shop.txt.txt_74629_3 = <iai:variable vid="dni"/>
app_shop.txt.txt_74629_4 = <iai:variable vid="godzin"/> + " "
app_shop.txt.txt_74629_5 = <iai:variable vid="minut"/> + " "
app_shop.txt.txt_74629_6 = <iai:variable vid="sekund"/> + " "
app_shop.txt.txt_74629_7 = <iai:variable vid="Przepraszamy, ale nie zdefiniowaliśmy standardowego kosztu dostawy, zostanie on ustalony indywidualnie przez naszą obsługę po przyjęciu zamówienia"/> + "."
var txt_shipping_8 = <iai:variable vid="dzisiaj!"/>
var txt_shipping_9 = <iai:variable vid="w poniedziałek"/> + " "
var txt_shipping_10 = <iai:variable vid="we wtorek"/> + " "
var txt_shipping_11 = <iai:variable vid="w środę"/> + " "
var txt_shipping_12 = <iai:variable vid="w czwartek"/> + " "
var txt_shipping_13 = <iai:variable vid="w piątek"/> + " "
var txt_shipping_14 = <iai:variable vid="w sobotę"/> + " "
var txt_shipping_15 = <iai:variable vid="w niedzielę"/> + " "
var txt_shipping_16 = <iai:variable vid="jutro!"/>
app_shop.txt.txt_74629_8 = <iai:variable vid="Wybierz rozmiar"/>
projectorObj.options['friendly_shipping_format'] = [txt_shipping_8, txt_shipping_9, txt_shipping_10, txt_shipping_11, txt_shipping_12, txt_shipping_13, txt_shipping_14, txt_shipping_15];
app_shop.txt.txt_74629_9 = <iai:variable vid="Twój produkt jest gotowy do wysyłki"/>;
app_shop.txt.txt_74629_10 = <iai:variable vid="Twój produkt jest już spakowany i gotowy do odebrania przez kuriera"/>;
app_shop.txt.txt_74629_11 = <iai:variable vid="Czas przygotowania produktu do wysyłki"/>;
app_shop.txt.txt_74629_12 = <iai:variable vid="Jest to czas, w którym produkt jest pakowany i przygotowywany do odebrania przez kuriera"/>;
app_shop.txt.txt_74629_13 = "";
app_shop.txt.txt_74629_14 = <iai:variable vid="Przygotowanie do odbioru osobistego zajmie do 24h"/>;
app_shop.txt.txt_74629_15 = <iai:variable vid="Przygotowanie do odbioru osobistego zajmie 24h"/>;
app_shop.txt.txt_74629_16 = <iai:variable vid="Przygotowanie do odbioru osobistego zajmie"/> + " ";
app_shop.txt.txt_74629_17 = <iai:variable vid="Przesyłka będzie u Ciebie dzisiaj!"/> + " ";
app_shop.txt.txt_74629_18 = <iai:variable vid="Przesyłka będzie u Ciebie jutro!"/>;
app_shop.txt.txt_74629_19 = <iai:variable vid="Przesyłka będzie u Ciebie za"/> + " ";
app_shop.txt.txt_74629_16467 = <iai:variable vid="Zamknij okno"/>;
var txt_62619_nieprawidlowy_email = <iai:variable vid="Niepoprawny adres email"/> + "."
var txt_62619_przekroczono_liczbe = <iai:variable vid="Przekroczono liczbę dodanych powiadomień w ciągu dnia"/> + "."
var txt_62619_podczas_dodawania = <iai:variable vid="Podczas dodawania produktu wystąpił błąd. Sprawdź poprawność wprowadzonych danych"/>
var txt_62619_produkt_dodany = <iai:variable vid="Produkt został poprawnie dodany do powiadomień"/> + "."
var txt_62619_blad_pobrania = <iai:variable vid="Wystąpił problem z połączeniem. Wykonaj czynność ponownie"/> + "."
var txt_62619_bledny_email = <iai:variable vid="Błędnie wpisany e-mail. Wpisz pełny adres e-mail, np. jan@kowalski.com"/> + " "
var txt_62619_wpisz_telefon = <iai:variable vid="Wpisz swój telefon"/> + ". "
var fashionGallery_new = "";
// Countdown timer
function CountdownTimer(elm, tl) {
this.initialize.apply(this, arguments);
}
CountdownTimer.prototype = {
initialize: function (elm, tl) {
this.elem = elm;
this.tl = tl;
this.tid = '';
},
newData: function (tl) {
this.tl = tl;
},
countDown: function () {
var timer = '';
var today = new Date();
var day = Math.floor((this.tl - today) / (24 * 60 * 60 * 1000));
var hour = Math.floor(((this.tl - today) % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000));
var min = Math.floor(((this.tl - today) % (24 * 60 * 60 * 1000)) / (60 * 1000)) % 60;
var sec = Math.floor(((this.tl - today) % (24 * 60 * 60 * 1000)) / 1000) % 60 % 60;
var me = this;
if ((this.tl - today) > 0) {
timer += '<label class="projector_label">' + app_shop.txt.txt_74629_1 + '</label><div>';
if (this.addZero(day) > 0)
timer += '<span class="number-wrapper"><div class="line"></div><div class="caption">' + app_shop.txt.txt_74629_3 + '</div><span class="number day">' + this.addZero(day) + '</span></span>';
timer += '<span class="number-wrapper"><div class="line"></div><div class="caption">' + app_shop.txt.txt_74629_4 + '</div><span class="number hour">' + this.addZero(hour) + '</span></span>';
timer += '<span class="number-wrapper"><div class="line"></div><div class="caption">' + app_shop.txt.txt_74629_5 + '</div><span class="number min">' + this.addZero(min) + '</span></span><span class="number-wrapper"><div class="line"></div><div class="caption">' + app_shop.txt.txt_74629_6 + '</div><span class="number sec">' + this.addZero(sec) + '</span></span></div>';
this.elem.html(timer);
this.tid = setTimeout(function () { me.countDown(); }, 1000);
} else {
clearTimeout(this.tid);
this.elem.remove();
return;
}
}, addZero: function (num) { return ('0' + num).slice(-2); }
}
class StationaryPanel {
constructor() {
this.panel = document.querySelector('.stationary__panel');
this.overlay = document.querySelector('.stationary__panel_overlay');
this.search = this.panel.querySelector('.stationary__panel_input');
this.searchWrapper = this.panel.querySelector('.stationary__panel_search');
this.body = document.querySelector('body');
this.template = document.querySelector('#stationary__panel_item_template');
this.geocoder = null; // Placeholder for geocoder if needed later
this.clientLocation = null;
this.clientCoords = null;
this.apiKey = 'gykxSsgNvghUsI0VSMXgPTZ00C2UQYN1KE3yJMrFGCrtUd2jXuFMfhnqzlDnsvzSlNCQBae08Vku0qDKC61HLGYRlaxvqm6V6IMyfv6dZxzlW2HIPA8i7XlcLj9Hkdtr';
this.navigatorGeolocationUsed = false;
this.nearMeLiteral = 'Blisko mnie';
this.pickupPointsData = [];
this.productSizes = null;
this.searchRadius = 100;
this.lastSearchValue = null;
this.fakeDataSizeS = [
{
'warehouse': 'ANDRESPOL',
"city": "Andrespol",
"street": "Rokicińska 130",
"postalCode": "95-020",
'quantity': 1,
},
{
"warehouse": "BRZEZINY",
"city": "Brzeziny",
"street": "Stefana Okrzei 14",
"postalCode": "95-060",
"quantity": 1
},
{
"warehouse": "GŁOWNO",
"city": "Głowno",
"street": "Sikoorskiego 59 C",
"postalCode": "95-015",
"quantity": 1
}
];
this.fakeDataSizeM = [
{
"warehouse": "ANDRESPOL",
"city": "Andrespol",
"street": "Rokicińska 130",
"postalCode": "95-020",
"quantity": 1
},
{
"warehouse": "BOLESŁAWIE",
"city": "Bolesławiec",
"street": "Asnyka 6/10",
"postalCode": "59-700",
"quantity": 1
},
{
"warehouse": "BRZEZINY",
"city": "Brzeziny",
"street": "Stefana Okrzei 14",
"postalCode": "95-060",
"quantity": 1
},
{
"warehouse": "BYDGOSZCZ2",
"city": "Bydgoszcz",
"street": "Fordońska 141 lok. 26",
"postalCode": "85-739",
"quantity": 1
},
{
"warehouse": "CHOJNICE",
"city": "Chojnice",
"street": "Kościuszki 7",
"postalCode": "89-600",
"quantity": 1
},
{
"warehouse": "CHOJNICE2",
"city": "Chojnice",
"street": "Reymonta 10",
"postalCode": "89-600",
"quantity": 1
},
{
"warehouse": "GŁOWNO",
"city": "Głowno",
"street": "Sikorskiego 59 C",
"postalCode": "95-015",
"quantity": 1
},
{
"warehouse": "JAWOR",
"city": "Jawor",
"street": "Rynek 27",
"postalCode": "59-400",
"quantity": 1
},
{
"warehouse": "KOZIENICE",
"city": "Kozienice",
"street": "Batalionów Chłopskich 18",
"postalCode": "26-900",
"quantity": 1
},
{
"warehouse": "KUTNO1",
"city": "Kutno",
"street": "Królewska31",
"postalCode": "99-300",
"quantity": 1
},
{
"warehouse": "LWÓWEK ŚL",
"city": "Lwówek Śląski",
"street": "Orzeszkowej 45",
"postalCode": "59-600",
"quantity": 1
},
{
"warehouse": "ŁASK1",
"city": "Łask",
"street": "Kościelna 5",
"postalCode": "98-100",
"quantity": 1
},
{
"warehouse": "ŁÓDŹ2",
"city": "Łódź",
"street": "Piłsudskiego 94",
"postalCode": "92-202",
"quantity": 1
},
{
"warehouse": "PIEKARY",
"city": "Piekary Śląskie",
"street": "1-go Maja 35",
"postalCode": "41-940",
"quantity": 1
},
{
"warehouse": "PIŁA2",
"city": "Piła",
"street": "1 Maja 5",
"postalCode": "64-920",
"quantity": 1
},
{
"warehouse": "RAWA MAZ2",
"city": "Rawa Mazowiecka",
"street": "Konstytucji 3-go Maja 2",
"postalCode": "96-200",
"quantity": 1
},
{
"warehouse": "RAWICZ1",
"city": "Rawicz",
"street": "17 styczeń 9/11",
"postalCode": "63-900",
"quantity": 1
},
{
"warehouse": "SKIERNIE 1",
"city": "Skierniewice",
"street": "Senatorska 3",
"postalCode": "96-100",
"quantity": 1
},
{
"warehouse": "TARNOBRZEG",
"city": "Tarnobrzeg",
"street": "Sienkiewicza 3",
"postalCode": "39-400",
"quantity": 1
},
{
"warehouse": "TRZCIANKA",
"city": "Trzcianka",
"street": "ul. Oś. XXV-lecia 14",
"postalCode": "64-980",
"quantity": 1
},
{
"warehouse": "WIELUŃ1",
"city": "Wieluń",
"street": "Warszawska 13",
"postalCode": "98-300",
"quantity": 1
},
{
"warehouse": "WYRZYSK",
"city": "Wyrzysk",
"street": "UL. Staszica 5",
"postalCode": "89-300",
"quantity": 1
},
{
"warehouse": "ZŁOTORYJA",
"city": "Złotoryja",
"street": "Rynek 8",
"postalCode": "59-500",
"quantity": 1
},
{
"warehouse": "ŻYRARDÓW1",
"city": "Żyrardów",
"street": "Mały Rynek 7/11",
"postalCode": "96-300",
"quantity": 1
}
]
}
// calculate distance between 2 points
haversineDistance(mk1, mk2) {
const R = 6371.0710; // Radius of the Earth in kilometers
const rlat1 = mk1.lat.toFixed(5) * (Math.PI/180); // Convert degrees to radians
const rlat2 = mk2.lat.toFixed(5) * (Math.PI/180); // Convert degrees to radians
const difflat = rlat2-rlat1; // Radian difference (latitudes)
const difflon = (mk2.lng.toFixed(5) - mk1.lng.toFixed(5)) * (Math.PI/180); // Radian difference (longitudes)
const d = 2 * R * Math.asin(Math.sqrt(Math.sin(difflat/2)*Math.sin(difflat/2)+Math.cos(rlat1)*Math.cos(rlat2)*Math.sin(difflon/2)*Math.sin(difflon/2)));
return d;
}
async initGeocoder() {
const { Geocoder } = await google.maps.importLibrary("geocoding");
this.geocoder = new google.maps.Geocoder();
}
showPanel() {
this.panel.classList.add('--open');
this.overlay.style.display = 'block';
this.body.classList.add('--no-scroll');
}
closePanel() {
this.panel.classList.remove('--open');
this.overlay.style.display = 'none';
this.body.classList.remove('--no-scroll');
}
updatePanelMessage(messageType = 'emptyLocation') {
const distanceMsgElement = document.querySelector('.stationary__panel_list_message_item[data-message-type="distance"]');
const notAvailableMsgElement = document.querySelector('.stationary__panel_list_message_item[data-message-type="notAvailable"]');
const emptyLocationMsgElement = document.querySelector('.stationary__panel_list_message_item[data-message-type="emptyLocation"]');
const noStoresMsgElement = document.querySelector('.stationary__panel_list_message_item[data-message-type="noStores"]');
// const msgWrapper = document.querySelector('.stationary__panel_list_message');
distanceMsgElement.textContent = distanceMsgElement.textContent.replace('%d', this.searchRadius);
if (messageType) this.panel.dataset.messageType = messageType;
else delete this.panel.dataset.messageType;
}
searchInputKeyupEvent() {
const clearButton = this.panel.querySelector('.icon_wrapper.--close');
const value = this.search.value;
this.navigatorGeolocationUsed = false;
if (value.length > 0) {
clearButton.style.display = 'block';
} else {
clearButton.style.display = 'none';
}
}
clearSearchInput() {
return this.search.value = '';
}
async searchEvent(searchValue = this.search.value.trim()) {
if (this.lastSearchValue !== null && this.lastSearchValue.trim() === this.search.value.trim()) return false;
this.searchWrapper.classList.add('--loading');
this.lastSearchValue = this.search.value.trim();
// await this.localizeAddress(this.search.value.trim());
await this.localizeAddress(searchValue);
await this.getPickupPointsData();
this.getPickupPointsDistance();
this.appendData();
this.updatePickupPointsDisplay();
this.searchWrapper.classList.remove('--loading');
this.search.classList.remove('--focused');
}
async searchInputSearchEvent() {
const address = this.search.value;
await this.localizeAddress(address);
this.findNearPickupPoints();
}
async findNearPickupPoints() {
//
}
// wylicza dystans między pickupPoint, a adresem klienta
getPickupPointsDistance() {
this.pickupPointsData.forEach((pickupPoint) => {
const idx = this.pickupPointsData.findIndex(
d => d.warehouse === pickupPoint.warehouse
);
const distance = this.haversineDistance(this.clientCoords, pickupPoint.coords);
this.pickupPointsData[idx].distance = distance;
});
}
// fetchujemy dane i wrzucamy do zbiorczego arraya z danymi
// dopisujemy size'y do obiektów
// dopisujemy koordynaty do obiektów
async getPickupPointsData() {
if (this.pickupPointsData !== null && Array.isArray(this.pickupPointsData) && this.pickupPointsData.length > 0) return true;
const sizes = this.productSizes;
const allPromises = sizes.map(async (size) => {
// tutaj będzie fetch, size podajemy jako jeden z parametrów
// funkcja fetch to osobna funkcja
// await response -> dla debuga używamy this.fakeDataSizeS i this.fakeDataSizeM
const myHeaders = new Headers();
myHeaders.append("x-api-key", "gykxSsgNvghUsI0VSMXgPTZ00C2UQYN1KE3yJMrFGCrtUd2jXuFMfhnqzlDnsvzSlNCQBae08Vku0qDKC61HLGYRlaxvqm6V6IMyfv6dZxzlW2HIPA8i7XlcLj9Hkdtr");
const requestOptions = {
method: 'GET',
headers: myHeaders,
redirect: 'follow',
};
let response = null;
const code = document.querySelector('.stationary__panel').dataset.code;
// const currentSize = projectorObj.currentSizeObj.name;
let url = `https://api2.moodo.pl:4547/api/salony/zasoby?kodTowaru=${code}; ${size}`;
try {
const res = await fetch(url, requestOptions);
if (!res.ok) {
// HTTP status not in the 200-299 range
throw new Error(`HTTP error! status: ${res.status}`);
}
response = await res.json();
} catch (error) {
// Handles both network errors and HTTP errors thrown above
console.error('Error fetching data:', error);
// Optionally rethrow or handle the error accordingly
}
// DEBUG
// Response to jest strzał po jeden rozmiar, dopisujemy sizes do każdego obiektu
// const response = size === 'S' ? this.fakeDataSizeS : this.fakeDataSizeM;
const pickupPromises = response.map(async (pickupPoint) => {
// dopisujemy size do obiektu z responsa
pickupPoint.sizes = [size];
// dopisujemy koordynaty
const pickupPointLocation = await this.getCoordinates(`${pickupPoint.postalCode} ${pickupPoint.city}, ${pickupPoint.street}`);
pickupPoint.coords = {lat: pickupPointLocation.location.geometry.location.lat(), lng: pickupPointLocation.location.geometry.location.lng()}
// dodajemy response do obiektu zbiorczego
// Szukamy indeksu magazynu w data
const idx = this.pickupPointsData.findIndex(
d => d.warehouse === pickupPoint.warehouse
);
if (idx !== -1) {
// Jeśli magazyn istnieje, dopisujemy size
if (this.pickupPointsData[idx].sizes) this.pickupPointsData[idx].sizes.push(size);
else this.pickupPointsData[idx].sizes = [size];
} else {
// Jeśli nie istnieje, dodajemy cały obiekt z responsa
this.pickupPointsData.push(pickupPoint);
}
});
// Poczekaj na wszystkie promisy dla danego rozmiaru
await Promise.all(pickupPromises);
});
// Poczekaj na wykonanie wszystkich rozmiarów
await Promise.all(allPromises);
}
async localizeAddress(address) {
// bez sensu jest ten IF, trza go wyjebać
if (this.navigatorGeolocationUsed !== true || this.clientCoords === null) {
// tutaj wyszukujemy coords klienta
const clientLocation = await this.getCoordinates(address);
this.clientLocation = clientLocation;
this.clientCoords = {lat: clientLocation.location.geometry.location.lat(), lng: clientLocation.location.geometry.location.lng()}
return clientLocation
}
}
async localizeMe() {
const errorMsg = {
1: 'Dostęp do lokalizacji został zablokowany na tym urządzeniu.',
2: 'Nie można określić lokalizacji.',
}
if (navigator.geolocation) {
return new Promise((resolve) => {
navigator.geolocation.getCurrentPosition(
(position) => {
resolve(position);
},
(error) => {
resolve(errorMsg[error.code] || errorMsg[2]);
}
);
});
} else {
return errorMsg[2];
}
}
async getCoordinates(address) {
if (!address) return false;
const isLatLng = /^-?\d+(?:\.\d+)?\s*,\s*-?\d+(?:\.\d+)?$/.test(address);
const params = new URLSearchParams();
if (isLatLng) {
const [lat, lng] = address.split(',').map(v => parseFloat(v.trim()));
params.set('lat', lat);
params.set('lng', lng);
} else {
params.set('q', address);
}
const t0 = (typeof performance !== 'undefined' && performance.now) ? performance.now() : Date.now();
let res, data;
try {
res = await fetch('https://serwer1852487.home.pl/Geo/?' + params.toString(), {
method: 'GET',
headers: { 'Accept': 'application/json' },
});
const t1 = (typeof performance !== 'undefined' && performance.now) ? performance.now() : Date.now();
if (!res.ok) throw new Error('Geocode API failed: ' + res.status);
data = await res.json();
if (!data || typeof data.lat !== 'number' || typeof data.lng !== 'number') {
throw new Error('Invalid geocode response');
}
// OK adapter
const src = data.source || (data.from_cache ? 'cache' : 'google');
const stale = data.stale ? ' (stale)' : '';
const ms = Math.round(t1 - t0);
return {
location: {
geometry: {
location: {
lat: () => data.lat,
lng: () => data.lng,
}
}
},
formatted_address: data.formatted_address || '',
place_id: data.place_id || '',
from_cache: !!data.from_cache,
source: src,
stale: !!data.stale,
};
} catch (err) {
// === fragment logiki ze starego kodu ===
const list = this.panel?.querySelector('.stationary__panel_list ul');
if (list) list.innerHTML = "";
this.searchWrapper?.classList.remove("--loading");
this.updatePanelMessage("noStores");
this.search?.classList.remove("--focused");
// zwracamy „pusty adapter”, żeby reszta kodu się nie wywaliła
return {
location: {
geometry: {
location: {
lat: () => null,
lng: () => null,
}
}
},
formatted_address: '',
place_id: '',
from_cache: false,
source: 'error',
stale: false,
};
}
}
async attachEvents() {
document.addEventListener('click', async (e) => {
// button ZNAJDŹ W SALONIE
if (e.target.closest('.projector_stationary__wrapper button')) {
e.preventDefault();
this.showPanel();
this.updatePanelMessage();
return;
}
// button X
if (e.target.closest('.stationary__panel_close')) {
e.preventDefault();
this.closePanel();
return;
}
// klik poza panel
if (this.panel.classList.contains('--open') && !e.target.closest('.stationary__panel')) {
this.closePanel();
return;
}
// klik w X w wyszukiwarce
if (e.target.closest('.icon_wrapper.--close')) {
e.preventDefault();
this.clearSearchInput();
this.searchInputKeyupEvent();
return;
}
// focus na wrapper wyszukiwarki
if (e.target.closest('.stationary__panel_search')) {
this.search.classList.add('--focused');
} else {
this.search.classList.remove('--focused');
}
// klik w SZUKAJ BLISKO MNIE
if (e.target.closest('.stationary__panel_search_localize:not(.--blocked)')) {
const localizeMeResponse = await this.localizeMe();
// console.log('localizeMeResponse: ', localizeMeResponse)
// DEBUG
// console.log('app_shop.vars.test: ', app_shop.vars.test)
// this.clientCoords = {
// lat: app_shop.vars.test.lat,
// lng: app_shop.vars.test.lng
// }
// this.search.value = this.nearMeLiteral;
// await this.searchEvent(`${this.clientCoords.lat}, ${this.clientCoords.lng}`);
// return;
// DEBUG END
if (typeof localizeMeResponse === 'string') {
// error
e.target.closest('.stationary__panel_search_localize').querySelector('span:not(.icon_wrapper)').textContent = localizeMeResponse;
e.target.closest('.stationary__panel_search_localize').classList.add('--blocked');
} else {
// success
console.log('localizeMeResponse.coords: ', localizeMeResponse.coords)
this.clientCoords = {
lat: localizeMeResponse.coords.latitude,
lng: localizeMeResponse.coords.longitude
}
this.search.value = this.nearMeLiteral;
await this.searchEvent(`${this.clientCoords.lat}, ${this.clientCoords.lng}`);
// this.search.dataset.lat = this.clientCoords.lat;
// this.search.dataset.lon = this.clientCoords.lon;
// this.navigatorGeolocationUsed = true;
}
}
// searchButton
if (e.target.closest('.stationary__panel_search_btn')) {
return await this.searchEvent();
}
});
this.search.addEventListener('keyup', async (e) => {
if (e.key === 'Enter') {
e.preventDefault();
return await this.searchEvent();
}
return this.searchInputKeyupEvent();
});
}
appendData(data = this.pickupPointsData) {
const list = this.panel.querySelector('.stationary__panel_list ul');
list.innerHTML = ''; // Clear previous results
if (!data || data.length === 0) {
this.updatePanelMessage('notAvailable');
return false;
}
data.sort((a, b) => a.distance - b.distance).forEach(item => {
const clone = this.template.content.cloneNode(true);
const itemElement = clone.querySelector('.stationary__panel_item');
// itemElement.dataset.id = item.warehouse;
itemElement.dataset.distance = item.distance.toFixed(1);
itemElement.dataset.sizes = item.sizes.toString().replaceAll(',', ', ');
const sizesOrder = ['XS', 'S', 'M', 'L', 'XL', 'XXL', 'XXXL', 'XXXXL']
itemElement.querySelector('.stationary__panel_item_name').textContent = `${item.city} - ${item.street}`;
itemElement.querySelector('.stationary__panel_item_sizes').textContent = item.sizes.sort((a, b) => sizesOrder.indexOf(a) - sizesOrder.indexOf(b)).toString().replaceAll(',', ', ');
itemElement.querySelector('.stationary__panel_item_distance').textContent = `${item.distance.toFixed(1)} KM`;
list.appendChild(clone);
});
}
// pokazujemy tylko w radiusie
updatePickupPointsDisplay() {
const itemsList = this.panel.querySelectorAll('.stationary__panel_list .stationary__panel_item');
const itemsListLength = itemsList.length;
let hiddenCounter = 0;
itemsList.forEach((item) => {
const distance = parseFloat(item.dataset.distance);
if (distance > this.searchRadius) {
item.classList.add('--hidden');
hiddenCounter++;
} else {
item.classList.remove('--hidden');
}
});
if (hiddenCounter === itemsListLength) this.updatePanelMessage('distance');
else this.updatePanelMessage(null);
return;
}
getProductSizes() {
// debug
// return this.productSizes = ['S', 'M'];
return this.productSizes = this.panel.dataset.sizes.split(',');
}
async init() {
this.getProductSizes();
this.attachEvents();
await this.initGeocoder();
}
}
app_shop.run(function () {
app_shop.fn.stationaryPanel = new StationaryPanel();
app_shop.fn.stationaryPanel.init();
}, 'all', '.projector_stationary__wrapper');