(() => {
'use strict';
const $=id=>document.getElementById(id),form=$('absenceFilters');
const esc=v=>String(v??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
const number=v=>Number(v).toLocaleString('da-DK',{maximumFractionDigits:2});
const hours=v=>number(v/60)+' t';
const date=v=>new Intl.DateTimeFormat('da-DK',{dateStyle:'short',timeStyle:'short',timeZone:'Europe/Copenhagen'}).format(new Date(v));
const day=v=>`${v.getFullYear()}-${String(v.getMonth()+1).padStart(2,'0')}-${String(v.getDate()).padStart(2,'0')}`;
let offset=0,requestVersion=0,filters=null,data=null;
const now=new Date();form.elements.start_date.value=day(new Date(now.getFullYear(),now.getMonth(),1));form.elements.end_date.value=day(new Date(now.getFullYear(),now.getMonth()+1,0));
window.BMCPlanningDates?.mount(form);
async function get(params) {
const response=await fetch('/api/v1/planner/absence-report?'+params,{headers:{Accept:'application/json'},credentials:'same-origin'});
const result=await response.json();if(!response.ok)throw new Error(typeof result.detail==='string'?result.detail:'Rapporten kunne ikke indlæses');return result;
}
function fail(err){$('absenceError').textContent=err.message;$('absenceError').hidden=false;}
async function load(newFilters=false) {
const version=++requestVersion;$('absenceError').hidden=true;$('absenceExport').disabled=true;$('absenceStatus').textContent='Henter fravær…';
if(newFilters){offset=0;filters=new URLSearchParams(new FormData(form));if(!filters.get('user_id'))filters.delete('user_id');filters.set('group_by','type');}
const params=new URLSearchParams(filters);params.set('offset',offset);params.set('limit',50);
try {
const result=await get(params);if(version!==requestVersion)return;data=result;
if(!form.elements.user_id.dataset.loaded){form.elements.user_id.insertAdjacentHTML('beforeend',result.employees.map(u=>``).join(''));form.elements.user_id.dataset.loaded='1';}
$('absenceTotals').innerHTML=[['Arbejdsdage',number(result.totals.planned_days)],['Planlagte timer',hours(result.totals.planned_minutes)],['Faktisk registreret fravær',hours(result.totals.actual_minutes)]].map(([label,value])=>`
`).join('');
const values=r=>`${r.norm_configured?number(r.planned_days):'Ukendt'} | ${r.norm_configured?hours(r.planned_minutes):'Ukendt'} | ${hours(r.actual_minutes)} | `;
$('absenceSummary').innerHTML=(result.type_summary||[]).map(group=>`| ${esc(group.kind_label)} · ${group.periods} perioder | ${values(group)}
`+group.employees.map(r=>`| ${esc(r.name)}${r.norm_configured?'':' · arbejdstid mangler'} | ${values(r)}
`).join('')).join('')||'| Intet fravær i den valgte periode. |
';
let previousKind=null;
$('absenceRows').innerHTML=result.items.map(r=>{
const heading=previousKind!==r.kind?`| ${esc(r.kind_label)} |
`:'';previousKind=r.kind;
return heading+`| ${esc(r.name)} | ${esc(r.kind_label)} | ${date(r.starts_at)} | ${date(r.ends_at)} | ${r.norm_configured?number(r.planned_days):'Ukendt'} | ${r.norm_configured?hours(r.planned_minutes):'Ukendt'} | ${hours(r.actual_minutes)} | ${r.registered?'Tid registreret':'Planlagt'} |
`;
}).join('')||'| Intet fravær i den valgte periode. |
';
$('absencePrev').disabled=offset===0;$('absenceNext').disabled=offset+result.items.length>=result.total;
$('absencePage').textContent=`${number(result.totals.planned_days)} arbejdsdage i alt · `+(result.total?`${offset+1}–${offset+result.items.length} af ${result.total} perioder`:'0 perioder');
$('absenceStatus').textContent=`${result.total} fraværsperioder. Planlagt og faktisk fravær vises separat.`;$('absenceExport').disabled=false;
}catch(err){if(version===requestVersion){data=null;$('absenceTotals').innerHTML='';$('absenceSummary').innerHTML='';$('absenceRows').innerHTML='';$('absencePrev').disabled=true;$('absenceNext').disabled=true;$('absenceStatus').textContent='';fail(err);}}
}
function csvCell(value) {
let text=String(value??'');if(/^[\s]*[=+\-@]/.test(text))text="'"+text;return '"'+text.replaceAll('"','""')+'"';
}
$('absenceExport').onclick=async()=>{
if(!data||!filters)return;$('absenceExport').disabled=true;
const exportFilters=new URLSearchParams(filters);
try {
let rows=[],page=0,total;
do {const params=new URLSearchParams(exportFilters);params.set('limit',500);params.set('offset',page);const result=await get(params);rows.push(...result.items);total=result.total;page+=result.items.length;if(!result.items.length&&page[r.kind_label,r.name,date(r.starts_at),date(r.ends_at),r.norm_configured?number(r.planned_days):'Ukendt',r.norm_configured?number(r.planned_minutes/60):'Ukendt',number(r.actual_minutes/60),r.registered?'Tid registreret':'Planlagt'])].map(r=>r.map(csvCell).join(';')).join('\r\n');
const url=URL.createObjectURL(new Blob(['\uFEFF'+content],{type:'text/csv;charset=utf-8'})),a=document.createElement('a');a.href=url;a.download=`fravaer-${exportFilters.get('start_date')}-${exportFilters.get('end_date')}.csv`;a.click();setTimeout(()=>URL.revokeObjectURL(url),1000);
}catch(err){fail(err);}finally{$('absenceExport').disabled=!data;}
};
form.onsubmit=e=>{e.preventDefault();load(true);};$('absencePrev').onclick=()=>{offset=Math.max(0,offset-50);load();};$('absenceNext').onclick=()=>{offset+=50;load();};load(true);
})();