poprawki dla bazy pilotów web, modul zaproszen w apce mobile

This commit is contained in:
oskarn
2026-09-21 16:17:27 +02:00
parent 8c42888f52
commit d17cba2bbb
37 changed files with 2271 additions and 833 deletions
File diff suppressed because it is too large Load Diff
+420
View File
@@ -0,0 +1,420 @@
/**
* Superpilot Web — Logika Wyszukiwarki i Filtrów w Stylu Pracuj.pl
* z Multiselectem Krajów w Górnej Belce oraz Bazą w Lewym Sidebarze
*/
document.addEventListener('DOMContentLoaded', function () {
initPracujFilters();
initTopDestMultiselect();
initDateRangeModal();
initModals();
});
function initPracujFilters() {
const searchInput = document.getElementById('mainSearchInput');
const executeBtn = document.getElementById('btnExecuteSearch');
const sidebarCheckboxes = document.querySelectorAll('.filter-checkbox');
const clearBtn = document.getElementById('btnClearAllFilters');
const sidebarCountSpan = document.getElementById('sidebarCountSpan');
const offersCountText = document.getElementById('offersCountText');
const noOffersAlert = document.getElementById('noOffersAlert');
const pilotCards = document.querySelectorAll('.pilot-grid-item');
window.currentDateFilter = '16-24-sep-2027';
function applyFilters() {
const query = searchInput ? searchInput.value.toLowerCase().trim() : '';
// Pobierz zaznaczone kraje z GÓRNEJ BELKI (Multiselect)
const selectedTopDests = Array.from(document.querySelectorAll('.top-dest-checkbox:checked')).map(cb => cb.value.toLowerCase());
// Pobierz zaznaczone checkboxy z SIDEBARA (w tym nowa Baza!)
const selectedBases = Array.from(document.querySelectorAll('.filter-checkbox[data-type="base"]:checked')).map(cb => cb.value.toLowerCase());
const selectedSpecs = Array.from(document.querySelectorAll('.filter-checkbox[data-type="spec"]:checked')).map(cb => cb.value.toLowerCase());
const selectedLangs = Array.from(document.querySelectorAll('.filter-checkbox[data-type="lang"]:checked')).map(cb => cb.value.toLowerCase());
const selectedCerts = Array.from(document.querySelectorAll('.filter-checkbox[data-type="cert"]:checked')).map(cb => cb.value.toLowerCase());
let visibleCount = 0;
pilotCards.forEach(card => {
const name = (card.getAttribute('data-name') || '').toLowerCase();
const base = (card.getAttribute('data-base') || '').toLowerCase();
const dests = (card.getAttribute('data-destinations') || '').toLowerCase();
const langs = (card.getAttribute('data-languages') || '').toLowerCase();
const tags = (card.getAttribute('data-tags') || '').toLowerCase();
const rating = parseFloat(card.getAttribute('data-rating') || '0');
const verified = card.getAttribute('data-verified') === '1';
const kpp = card.getAttribute('data-kpp') === '1';
const datesFree = (card.getAttribute('data-dates-free') || '');
let match = true;
// 1. Wyszukiwanie tekstowe
if (query && !name.includes(query) && !dests.includes(query) && !tags.includes(query) && !langs.includes(query) && !base.includes(query)) {
match = false;
}
// 2. Destynacje z Multiselecta u góry
if (selectedTopDests.length > 0) {
const hasAnyDest = selectedTopDests.some(d => dests.includes(d));
if (!hasAnyDest) match = false;
}
// 3. Baza wypadowa z sidebara
if (selectedBases.length > 0) {
const hasAnyBase = selectedBases.some(b => base.includes(b));
if (!hasAnyBase) match = false;
}
// 4. Specjalizacje z sidebara
if (selectedSpecs.length > 0) {
const hasAnySpec = selectedSpecs.some(s => tags.includes(s));
if (!hasAnySpec) match = false;
}
// 5. Języki z sidebara
if (selectedLangs.length > 0) {
const hasAnyLang = selectedLangs.some(l => langs.includes(l));
if (!hasAnyLang) match = false;
}
// 6. Certyfikaty z sidebara
if (selectedCerts.includes('verified') && !verified) match = false;
if (selectedCerts.includes('kpp') && !kpp) match = false;
if (selectedCerts.includes('rating-48') && rating < 4.8) match = false;
// 7. Kalendarz
if (window.currentDateFilter === '16-24-sep-2027') {
if (!datesFree.includes('16-24-sep') && name !== 'oskar kaczmarek') {
match = false;
}
} else if (window.currentDateFilter === '05-15-sep-2027') {
if (!datesFree.includes('05-15-sep')) {
match = false;
}
} else if (window.currentDateFilter === 'październik-2027') {
if (!datesFree.includes('październik-2027')) {
match = false;
}
}
if (match) {
card.style.display = 'flex';
visibleCount++;
} else {
card.style.display = 'none';
}
});
// Aktualizacja liczników
if (sidebarCountSpan) sidebarCountSpan.innerText = visibleCount;
if (offersCountText) offersCountText.innerText = visibleCount + (visibleCount === 1 ? ' oferta' : (visibleCount >= 2 && visibleCount <= 4 ? ' oferty' : ' ofert'));
if (noOffersAlert) noOffersAlert.style.display = (visibleCount === 0) ? 'block' : 'none';
// Aktualizacja paska aktywnych filtrów (Chips)
updateActiveFilterChips(selectedTopDests, selectedBases);
}
if (searchInput) searchInput.addEventListener('input', applyFilters);
if (executeBtn) executeBtn.addEventListener('click', applyFilters);
sidebarCheckboxes.forEach(cb => {
cb.addEventListener('change', applyFilters);
});
const applySidebarBtn = document.getElementById('btnApplySidebarFilters');
if (applySidebarBtn) {
applySidebarBtn.addEventListener('click', function () {
applyFilters();
window.scrollTo({ top: 0, behavior: 'smooth' });
});
}
if (clearBtn) {
clearBtn.addEventListener('click', function () {
if (searchInput) searchInput.value = '';
sidebarCheckboxes.forEach(cb => cb.checked = false);
document.querySelectorAll('.top-dest-checkbox').forEach(cb => cb.checked = false);
updateDestTriggerLabel();
window.currentDateFilter = 'all';
const display = document.getElementById('selectedDateDisplay');
if (display) display.value = 'Dowolny termin';
applyFilters();
});
}
// Obsługa usunięcia chipa bazy
const removeBaseChip = document.getElementById('removeBaseChip');
if (removeBaseChip) {
removeBaseChip.addEventListener('click', function () {
document.querySelectorAll('.filter-checkbox[data-type="base"]').forEach(cb => cb.checked = false);
applyFilters();
});
}
window.triggerSuperpilotFilter = applyFilters;
}
function initTopDestMultiselect() {
const destCheckboxes = document.querySelectorAll('.top-dest-checkbox');
const triggerText = document.getElementById('destTriggerText');
const resetBtn = document.getElementById('btnResetDestMultiselect');
const confirmBtn = document.getElementById('btnConfirmDestDropdown');
function updateLabel() {
const checked = Array.from(document.querySelectorAll('.top-dest-checkbox:checked')).map(cb => cb.value);
if (!triggerText) return;
if (checked.length === 0) {
triggerText.innerText = 'Wszystkie kraje';
triggerText.style.color = '#94a3b8';
} else if (checked.length === 1) {
const flag = getCountryFlag(checked[0]);
triggerText.innerText = flag + ' ' + checked[0];
triggerText.style.color = 'var(--dark-navy)';
} else if (checked.length === 2) {
triggerText.innerText = checked.map(c => getCountryFlag(c) + ' ' + c).join(', ');
triggerText.style.color = 'var(--dark-navy)';
} else {
triggerText.innerText = getCountryFlag(checked[0]) + ' ' + checked[0] + ' (+' + (checked.length - 1) + ' inne)';
triggerText.style.color = 'var(--dark-navy)';
}
if (window.triggerSuperpilotFilter) window.triggerSuperpilotFilter();
}
window.updateDestTriggerLabel = updateLabel;
destCheckboxes.forEach(cb => {
cb.addEventListener('change', updateLabel);
});
if (resetBtn) {
resetBtn.addEventListener('click', function () {
destCheckboxes.forEach(cb => cb.checked = false);
updateLabel();
});
}
if (confirmBtn) {
confirmBtn.addEventListener('click', function () {
const dropdownEl = document.getElementById('destDropdownTrigger');
const dropdown = bootstrap.Dropdown.getInstance(dropdownEl);
if (dropdown) dropdown.hide();
});
}
const removeDestChip = document.getElementById('removeDestChip');
if (removeDestChip) {
removeDestChip.addEventListener('click', function () {
destCheckboxes.forEach(cb => cb.checked = false);
updateLabel();
});
}
}
function updateActiveFilterChips(selectedDests, selectedBases) {
const chipDest = document.getElementById('chipDestFilter');
const chipDestText = document.getElementById('chipDestText');
const chipDate = document.getElementById('chipDateFilter');
const chipDateText = document.getElementById('chipDateText');
const chipBase = document.getElementById('chipBaseFilter');
const chipBaseText = document.getElementById('chipBaseText');
if (chipDest && chipDestText) {
if (selectedDests && selectedDests.length > 0) {
chipDest.style.display = 'inline-flex';
chipDestText.innerText = selectedDests.map(d => capitalize(d)).join(', ');
} else {
chipDest.style.display = 'none';
}
}
if (chipDate && chipDateText) {
if (window.currentDateFilter && window.currentDateFilter !== 'all') {
chipDate.style.display = 'inline-flex';
if (window.currentDateFilter === '16-24-sep-2027') chipDateText.innerText = '16–24.09.2027';
else if (window.currentDateFilter === '05-15-sep-2027') chipDateText.innerText = '05–15.09.2027';
else if (window.currentDateFilter === 'październik-2027') chipDateText.innerText = 'Październik 2027';
} else {
chipDate.style.display = 'none';
}
}
if (chipBase && chipBaseText) {
if (selectedBases && selectedBases.length > 0) {
chipBase.style.display = 'inline-flex';
chipBaseText.innerText = 'Baza: ' + selectedBases.map(b => capitalize(b)).join(', ');
} else {
chipBase.style.display = 'none';
}
}
}
function initDateRangeModal() {
const presets = document.querySelectorAll('.preset-chip');
const selectedText = document.getElementById('modalSelectedDateText');
const displayInput = document.getElementById('selectedDateDisplay');
const resetDateBtn = document.getElementById('btnResetDateDialog');
const applyDateBtn = document.getElementById('btnApplyDateDialog');
const removeDateChip = document.getElementById('removeDateChip');
presets.forEach(p => {
p.addEventListener('click', function () {
presets.forEach(item => item.classList.remove('active'));
this.classList.add('active');
const presetVal = this.getAttribute('data-preset');
window.currentDateFilter = presetVal;
if (presetVal === '16-24-sep-2027') {
selectedText.innerText = '16.09.2027 – 24.09.2027 (Wycieczka #12)';
displayInput.value = '16.09.2027 – 24.09.2027';
} else if (presetVal === '05-15-sep-2027') {
selectedText.innerText = '05.09.2027 – 15.09.2027 (Wolne okienko)';
displayInput.value = '05.09.2027 – 15.09.2027';
} else if (presetVal === 'październik-2027') {
selectedText.innerText = '01.10.2027 – 31.10.2027 (Październik)';
displayInput.value = 'Październik 2027';
} else {
selectedText.innerText = 'Dowolny termin';
displayInput.value = 'Dowolny termin';
}
});
});
if (resetDateBtn) {
resetDateBtn.addEventListener('click', function () {
presets.forEach(item => item.classList.remove('active'));
const allPreset = document.querySelector('.preset-chip[data-preset="all"]');
if (allPreset) allPreset.classList.add('active');
window.currentDateFilter = 'all';
selectedText.innerText = 'Dowolny termin';
displayInput.value = 'Dowolny termin';
if (window.triggerSuperpilotFilter) window.triggerSuperpilotFilter();
const modalEl = document.getElementById('dateRangeModal');
const modalInstance = bootstrap.Modal.getInstance(modalEl);
if (modalInstance) modalInstance.hide();
});
}
if (applyDateBtn) {
applyDateBtn.addEventListener('click', function () {
if (window.triggerSuperpilotFilter) window.triggerSuperpilotFilter();
});
}
if (removeDateChip) {
removeDateChip.addEventListener('click', function () {
window.currentDateFilter = 'all';
displayInput.value = 'Dowolny termin';
if (window.triggerSuperpilotFilter) window.triggerSuperpilotFilter();
});
}
}
function initModals() {
window.openBookingModal = function (pilotId, pilotName, dates) {
const modal = new bootstrap.Modal(document.getElementById('bookingModal'));
const nameInput = document.getElementById('bookingPilotName');
const nameDisplay = document.getElementById('bookingPilotNameDisplay');
const idInput = document.getElementById('bookingPilotId');
const datesInput = document.getElementById('bookingDates');
const name = pilotName || 'Oskar Kaczmarek';
if (nameInput) nameInput.value = name;
if (nameDisplay) nameDisplay.innerText = name;
if (idInput) idInput.value = pilotId || '1';
if (datesInput && dates) datesInput.value = dates;
modal.show();
};
window.openSosModal = function (defaultCountry) {
const modal = new bootstrap.Modal(document.getElementById('sosModal'));
if (defaultCountry && document.getElementById('sosCountrySelect')) {
document.getElementById('sosCountrySelect').value = defaultCountry;
}
modal.show();
};
const bookingForm = document.getElementById('pilotBookingForm');
if (bookingForm) {
bookingForm.addEventListener('submit', function (e) {
e.preventDefault();
const submitBtn = bookingForm.querySelector('button[type="submit"]');
const pilotName = document.getElementById('bookingPilotName').value;
const originalText = submitBtn.innerHTML;
submitBtn.disabled = true;
submitBtn.innerHTML = "<span class=\"spinner-border spinner-border-sm me-1\"></span> Wysyłanie powiadomienia PUSH...";
setTimeout(() => {
submitBtn.disabled = false;
submitBtn.innerHTML = originalText;
const modalEl = document.getElementById('bookingModal');
const modalInstance = bootstrap.Modal.getInstance(modalEl);
if (modalInstance) modalInstance.hide();
showToastNotification(
'Pomyślnie wysłano zapytanie!',
'Powiadomienie PUSH trafiło do aplikacji mobilnej pilota (' + pilotName + '). Pilot ma 24h na akceptację w aplikacji.'
);
}, 900);
});
}
}
function showToastNotification(title, message) {
let container = document.getElementById('toastContainer');
if (!container) {
container = document.createElement('div');
container.id = 'toastContainer';
container.style.position = 'fixed';
container.style.top = '24px';
container.style.right = '24px';
container.style.zIndex = '99999';
document.body.appendChild(container);
}
const toast = document.createElement('div');
toast.className = 'toast show align-items-center text-white bg-dark border-0 mb-2 shadow-lg';
toast.style.minWidth = '340px';
toast.style.borderRadius = '12px';
toast.style.overflow = 'hidden';
toast.innerHTML = `
<div class="d-flex p-3" style="background: linear-gradient(135deg, #1f2244 0%, #312e81 100%);">
<div class="me-3 fs-3 text-warning">
<i class='bx bxs-bell-ring'></i>
</div>
<div class="flex-grow-1">
<h6 class="fw-bold mb-1 text-white" style="font-size: 0.92rem;">${title}</h6>
<div style="font-size: 0.8rem; line-height: 1.4; color: #cbd5e1;">${message}</div>
</div>
<button type="button" class="btn-close btn-close-white me-1 m-auto" onclick="this.closest('.toast').remove()"></button>
</div>
`;
container.appendChild(toast);
setTimeout(() => {
toast.remove();
}, 6000);
}
function getCountryFlag(country) {
const map = {
'Włochy': '🇮🇹',
'Grecja': '🇬🇷',
'Hiszpania': '🇪🇸',
'Chorwacja': '🇭🇷',
'Norwegia': '🇳🇴',
'Austria': '🇦🇹',
'Japonia': '🇯🇵'
};
return map[country] || '🌍';
}
function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}