moving closer to something useful

This commit is contained in:
2026-08-22 23:41:18 +01:00
parent a7cd06d40d
commit e95a5b1a9f
5 changed files with 628 additions and 78 deletions
+174 -14
View File
@@ -351,15 +351,92 @@ async function fetchData(endpoint) {
}
}
function populateSelect(id, items, codeKey, labelKey) {
const sel = document.getElementById(id);
sel.innerHTML = '<option value="">All</option>';
function populateDropdown(containerId, items, codeKey, labelKey) {
const container = document.getElementById(containerId);
if (!container) return;
const checkboxList = container.querySelector('.checkbox-dropdown-list');
checkboxList.innerHTML = '';
const selectAllLabel = document.createElement('label');
selectAllLabel.className = 'checkbox-item select-all-wrapper';
selectAllLabel.innerHTML = `
<input type="checkbox" class="select-all" data-target="${containerId}" checked>
<span>All</span>
`;
checkboxList.appendChild(selectAllLabel);
const separator = document.createElement('div');
separator.className = 'dropdown-separator';
checkboxList.appendChild(separator);
items.forEach((item) => {
const opt = document.createElement('option');
opt.value = item[codeKey];
opt.textContent = item[labelKey];
sel.appendChild(opt);
const label = document.createElement('label');
label.className = 'checkbox-item';
label.innerHTML = `
<input type="checkbox"
name="${containerId}"
value="${item[codeKey]}"
data-label="${item[labelKey]}">
<span>${item[labelKey]}</span>
`;
checkboxList.appendChild(label);
});
const selectAllCb = selectAllLabel.querySelector('.select-all');
selectAllCb.addEventListener('change', (e) => {
const cbs = checkboxList.querySelectorAll(`input[name="${containerId}"]`);
cbs.forEach(cb => {
if (!cb.disabled) {
cb.checked = e.target.checked;
}
});
updateDropdownLabel(containerId);
});
checkboxList.querySelectorAll(`input[name="${containerId}"]`).forEach(cb => {
cb.addEventListener('change', () => updateDropdownLabel(containerId));
});
updateDropdownLabel(containerId);
}
function updateDropdownLabel(containerId) {
const container = document.getElementById(containerId);
if (!container) return;
const cbs = container.querySelectorAll(`input[name="${containerId}"]`);
const checked = Array.from(cbs).filter(cb => cb.checked && !cb.disabled);
const labelEl = container.querySelector('.dropdown-label');
if (checked.length === 0) {
labelEl.textContent = 'None selected';
} else if (checked.length === cbs.length) {
labelEl.textContent = 'All selected';
} else {
labelEl.textContent = `${checked.length} selected`;
}
}
function toggleDropdown(containerId) {
const container = document.getElementById(containerId);
if (!container) return;
const list = container.querySelector('.checkbox-dropdown-list');
const isOpen = list.classList.contains('open');
document.querySelectorAll('.checkbox-dropdown-list.open').forEach(el => {
el.classList.remove('open');
});
if (!isOpen) {
list.classList.add('open');
}
}
function getSelectedValues(groupName) {
const checkboxes = document.querySelectorAll(`input[name="${groupName}"]:checked`);
return Array.from(checkboxes).filter(cb => !cb.disabled).map(cb => cb.value);
}
function populateMonthSelect(selectId, months) {
@@ -383,15 +460,15 @@ async function populateDropdowns() {
]);
if (speciesList) {
populateSelect('species', speciesList, 'code', 'label');
populateDropdown('species', speciesList, 'code', 'label');
}
if (zonesList) {
populateSelect('zone', zonesList, 'code', 'label');
populateDropdown('zone', zonesList, 'code', 'label');
}
if (gearList) {
populateSelect('gear', gearList, 'code', 'label');
populateDropdown('gear', gearList, 'code', 'label');
}
if (summaryData && summaryData.monthly) {
@@ -405,16 +482,62 @@ async function populateDropdowns() {
document.getElementById('month_to').value = allMonths[allMonths.length - 1];
}
await updateAvailableFilters();
showLoading(false);
}
async function updateAvailableFilters() {
const species = getSelectedValues('species');
const zone = getSelectedValues('zone');
const gear = getSelectedValues('gear');
const monthFrom = document.getElementById('month_from').value;
const monthTo = document.getElementById('month_to').value;
const params = new URLSearchParams();
if (species.length > 0) params.append('species_multi', species.join(','));
if (zone.length > 0) params.append('zone_multi', zone.join(','));
if (gear.length > 0) params.append('gear_multi', gear.join(','));
if (monthFrom) params.append('month_from', monthFrom);
if (monthTo) params.append('month_to', monthTo);
const available = await fetchData(`/api/available-filters?${params.toString()}`);
if (available) {
disableUnavailableOptions('species', available.species);
disableUnavailableOptions('zone', available.zones);
disableUnavailableOptions('gear', available.gear);
}
}
function disableUnavailableOptions(containerId, availableCodes) {
const container = document.getElementById(containerId);
if (!container) return;
const checkboxes = container.querySelectorAll(`input[type="checkbox"]`);
checkboxes.forEach(cb => {
if (cb.classList.contains('select-all')) return;
const isAvailable = availableCodes.includes(cb.value);
cb.disabled = !isAvailable;
cb.parentElement.style.opacity = isAvailable ? '1' : '0.4';
cb.parentElement.style.cursor = isAvailable ? 'pointer' : 'not-allowed';
if (!isAvailable && cb.checked) {
cb.checked = false;
}
});
updateDropdownLabel(containerId);
}
async function updateCharts() {
showLoading(true);
hideEmptyState();
const species = document.getElementById('species').value;
const zone = document.getElementById('zone').value;
const gear = document.getElementById('gear').value;
const species = getSelectedValues('species');
const zone = getSelectedValues('zone');
const gear = getSelectedValues('gear');
const monthFrom = document.getElementById('month_from').value;
const monthTo = document.getElementById('month_to').value;
@@ -425,7 +548,9 @@ async function updateCharts() {
}
const summaryParams = new URLSearchParams();
if (species) summaryParams.append('species', species);
if (species.length > 0) summaryParams.append('species_multi', species.join(','));
if (zone.length > 0) summaryParams.append('zone_multi', zone.join(','));
if (gear.length > 0) summaryParams.append('gear_multi', gear.join(','));
if (monthFrom) summaryParams.append('month_from', monthFrom);
if (monthTo) summaryParams.append('month_to', monthTo);
@@ -526,6 +651,15 @@ function hideEmptyState() {
document.getElementById('apply-filters').addEventListener('click', updateCharts);
// Close dropdowns when clicking outside
document.addEventListener('click', (e) => {
if (!e.target.closest('.filter-group.multi-select')) {
document.querySelectorAll('.checkbox-dropdown-list.open').forEach(el => {
el.classList.remove('open');
});
}
});
(() => {
function currentSystemTheme() {
return window.matchMedia('(prefers-color-scheme: dark)').matches
@@ -558,5 +692,31 @@ document.getElementById('apply-filters').addEventListener('click', updateCharts)
document.addEventListener('DOMContentLoaded', () => {
initCharts();
// Setup click handlers for dropdown toggles
['species', 'zone', 'gear'].forEach(id => {
const container = document.getElementById(id);
if (container) {
const label = container.querySelector('.dropdown-label');
if (label) {
label.addEventListener('click', (e) => {
e.stopPropagation();
toggleDropdown(id);
});
}
// Listen for changes inside the dropdown list
const list = container.querySelector('.checkbox-dropdown-list');
if (list) {
list.addEventListener('change', () => {
updateAvailableFilters();
});
}
}
});
document.getElementById('month_from').addEventListener('change', updateAvailableFilters);
document.getElementById('month_to').addEventListener('change', updateAvailableFilters);
populateDropdowns().then(updateCharts);
});