';
if (this.addZero(day) > 0)
timer += '
' + app_shop.txt.txt_74629_3 + '
' + this.addZero(day) + '';
timer += '
' + app_shop.txt.txt_74629_4 + '
' + this.addZero(hour) + '';
timer += '
' + app_shop.txt.txt_74629_5 + '
' + this.addZero(min) + '' + app_shop.txt.txt_74629_6 + '
' + this.addZero(sec) + ' ';
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');