const standardPrograms = ['SARI', 'ILI', 'LBM', 'AFI', 'NDS'];
const programCode = (window.PROGRAM_CODE || '').trim().toUpperCase();
let map;
document.addEventListener("DOMContentLoaded", () => {
if (!standardPrograms.includes(programCode)) return;
new DashboardFilter((startYear, startWeek, endYear, endWeek) => {
const elements = document.querySelectorAll(".report-period");
elements.forEach(el => {
el.textContent = 'Week ' + startWeek + ' of ' + startYear + ' to ' + 'Week ' + endWeek + ' of ' + endYear
});
fetch(`/api/dashboard/program?surveillance_id=${window.SURVEILLANCE_ID}&start_year=${startYear}&start_week=${startWeek}&end_year=${endYear}&end_week=${endWeek}`)
.then(res => res.json())
.then(programCode === 'AFI' ? renderAFIDashboard : renderDashboard)
.catch(err => console.error("Dashboard API error:", err));
});
});
function normalizeProvince(name, validSet) {
if (!name || !validSet) return null;
const clean = str =>
str.toLowerCase().replace(/\s+/g, '');
const raw = name.trim();
const map = {
"kepville": "Kep",
"sihanoukville": "Preah Sihanouk",
"sihanoukvillecity": "Preah Sihanouk",
"krongpailin": "Pailin",
"mondulkiri": "Mondulkiri",
"odormeanchey": "Oddar Meanchey",
"tbongkhmom": "Tboung Khmum",
"tboungkhmum": "Tboung Khmum",
"rattanakiri": "Ratanak Kiri"
};
const key = clean(raw);
if (map[key] && validSet.has(map[key])) {
return map[key];
}
const match = [...validSet].find(p => clean(p) === key);
return match || null;
}
function renderAFIDashboard(data) {
const pathogenRows = (data.pathogen_distribution || [])
.sort((a, b) => b.total - a.total);
const colors = [
'#2563eb', '#10b981', '#f59e0b', '#ef4444',
'#8b5cf6', '#14b8a6', '#f97316', '#84cc16', '#e11dba', '#f6f63b'
];
const rows = data.afi_trend || [];
const pcr = rows.filter(r => r.test_type === 'PCR');
const serum = rows.filter(r => r.test_type === 'Serum');
renderAFITrend(pcr, 'trendChart', colors);
//renderAFITrend(serum, 'pathogenChart', colors);
renderSummary(data.summary);
renderProvinceHeatmap(data.province_distribution);
renderDemographics(data);
renderPathogenChart(data.pathogen_distribution || []);
renderSentinel(data.sentinel_sites || []);
renderSubtypeChart(data.subtype_distribution || []);
charts['ageChart'].data.datasets[0].backgroundColor = colors;
charts['ageChart'].update();
charts['sexChart'].data.datasets[0].backgroundColor = colors;
charts['sexChart'].update();
charts['sentinelChart'].data.datasets[0].backgroundColor = colors;
charts['sentinelChart'].update();
charts['subtypeChart'].data.datasets[0].backgroundColor = colors;
charts['subtypeChart'].update();
charts['pathogenChart'].data.datasets[0].backgroundColor = colors;
charts['pathogenChart'].update();
}
function renderProvinceHeatmap(rows) {
window.latestProvinceData = rows;
if (map) map.remove();
map = L.map('provinceMap').setView([12.7, 104.9], 7);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
addProvinceLegend();
fetch('/geo/cambodia_provinces.geojson')
.then(r => r.json())
.then(geo => {
const validProvinces = new Set(
geo.features.map(f => f.properties.ADM1_EN)
);
window.validProvinces = validProvinces;
const totals = {};
rows.forEach(r => {
const province = normalizeProvince(r.patient_province, validProvinces);
if (!province) return;
if (!totals[province]) {
totals[province] = { total: 0, positive: 0 };
}
totals[province].total += Number(r.total);
totals[province].positive += Number(r.positive);
});
function getColor(value) {
if (value > 50) return "#b91c1c";
if (value >= 10) return "#ef4444";
if (value > 0) return "#fecaca";
return "#f3f4f600";
}
window.provinceLayer = L.geoJSON(geo, {
style: feature => {
const province = feature.properties.ADM1_EN;
const value = totals[province]?.total || 0;
return {
color: "#444",
weight: 1.5,
fillColor: getColor(value),
fillOpacity: 0.8
};
},
onEachFeature: (feature, layer) => {
const province = feature.properties.ADM1_EN;
const total = totals[province]?.total || 0;
const positive = totals[province]?.positive || 0;
const percent = total
? ((positive / total) * 100).toFixed(1)
: 0;
layer.bindTooltip(`
${province}
Total: ${total}
Positivity: ${percent}%
`);
}
}).addTo(map);
});
}
function addProvinceLegend() {
const legend = L.control({ position: "bottomright" });
legend.onAdd = function () {
const div = L.DomUtil.create("div", "map-legend");
div.innerHTML = `