V8 MEGA: meta endpoints + manifestacije + HNS V8 harvester batch

Endpoints:
- /v2/potpore/meta — dropdown options (sportovi, vrste, davatelji, godine)
- /v2/potpore/by-year — sport, vrsta filters
- /v2/manifestacije/meta — mjesta, razine, organizatori
- /v2/manifestacije — lista s filterima

HNS:
- 20 PGŽ priority klubova batch harvester pokrenut (HNK Goranin, HNK Orijent 1919, HNK Rijeka, NK Crikvenica, ...)
- ETA 30 min
This commit is contained in:
2026-05-05 18:10:02 +02:00
parent f07fdad919
commit a428363d42
6 changed files with 360 additions and 6 deletions
+23 -5
View File
@@ -1397,6 +1397,7 @@ function applySaveziFilter(){
else if(fKat==='gradski') rows = rows.filter(s => /gradsk/i.test(s.razina||''));
if(pgz==='1') rows = rows.filter(s => s.pgz_relevant);
if(_sort.savezi) rows = sortRows(rows, _sort.savezi.key, _sort.savezi.dir);
_filtersUpdateCount('savezi', rows.length);
$('#sav-cnt').textContent = rows.length+' saveza';
$('#sav-out').innerHTML = _state.viewSavezi==='card' ? renderSaveziGrid(rows) : renderSaveziTable(rows);
}
@@ -1887,13 +1888,28 @@ async function loadSportasi(){
const root = $('#pg-sportasi');
if(!_cache.clanovi){
root.innerHTML = '<div class="loading">Učitavanje sportaša…</div>';
// PGŽ filter: switch to v2 priority-sort (joins club, marks priority)
const url = window._pgz_filter_priority
? '/v2/clanovi/priority-sort?only=true&limit=2000'
: '/clanovi-full?limit=500';
// BUG-E (2026-05-05): explicit filter via /v2/sportasi/filtered.
// Priority + HNS profil + godina_rod_od/do are server-side params.
const f = _filters.sportasi;
const useFiltered = f.priority || f.hns_profil || f.godina_od || f.godina_do;
let url;
if(useFiltered){
const qs = new URLSearchParams();
qs.set('limit','2000');
if(f.priority) qs.set('samo_priority','true');
if(f.hns_profil) qs.set('samo_s_hns','true');
if(f.godina_od) qs.set('godina_rod_od', String(f.godina_od));
if(f.godina_do) qs.set('godina_rod_do', String(f.godina_do));
url = '/v2/sportasi/filtered?'+qs.toString();
} else if(window._pgz_filter_priority){
url = '/v2/clanovi/priority-sort?only=true&limit=2000';
} else {
url = '/clanovi-full?limit=500';
}
const d = await api(url);
if(!d){ root.innerHTML='<div class="empty">Greška pri dohvatu</div>'; return; }
_cache.clanovi = d.rows || [];
_filters.sportasi.total = (d.rows||[]).length;
}
renderSportasiShell();
applySportasiFilter();
@@ -1901,9 +1917,10 @@ async function loadSportasi(){
function renderSportasiShell(){
const root = $('#pg-sportasi');
const sports = Array.from(new Set((_cache.clanovi||[]).map(c=>c.sport).filter(Boolean))).sort();
const klubovi = Array.from(new Map((_cache.clanovi||[]).filter(c=>c.klub_id).map(c=>[c.klub_id, c.klub_naziv_godisnjak||('Klub #'+c.klub_id)])).entries()).sort((a,b)=>String(a[1]).localeCompare(String(b[1]),'hr'));
const klubovi = Array.from(new Map((_cache.clanovi||[]).filter(c=>c.klub_id).map(c=>[c.klub_id, c.klub_naziv_godisnjak||c.klub_naziv||('Klub #'+c.klub_id)])).entries()).sort((a,b)=>String(a[1]).localeCompare(String(b[1]),'hr'));
const kats = Array.from(new Set((_cache.clanovi||[]).flatMap(c => (c.kategorije && c.kategorije.length ? c.kategorije : [c.kategorija]).filter(Boolean)))).sort();
root.innerHTML = `
${_filtersBar('sportasi')}
<div class="toolbar">
<input type="search" id="sp-q" placeholder="🔍 Ime ili prezime…">
<select id="sp-sport"><option value="">Svi sportovi</option>${sports.map(s=>'<option value="'+esc(s)+'">'+esc(s)+'</option>').join('')}</select>
@@ -2050,6 +2067,7 @@ function applySportasiFilter(){
if(_state.spExtraAktivan==='false') rows = rows.filter(c => !c.aktivan);
if(_state.spExtraStipendiran) rows = rows.filter(c => c.stipendiran);
if(_sort.sportasi) rows = sortRows(rows, _sort.sportasi.key, _sort.sportasi.dir);
_filtersUpdateCount('sportasi', rows.length);
$('#sp-cnt').textContent = rows.length+' sportaša';
const top = rows.slice(0, 300);
$('#sp-out').innerHTML = _state.viewSportasi==='card' ? renderSportasiGrid(top) : renderSportasiTable(top);