`${escapeText(u.display_name||u.username)}${escapeText(u.username)}
${u.role==='admin'?'Admin':'Benutzer'} `).join('');$$('.user-password').forEach(b=>b.addEventListener('click',()=>openPassword(b.closest('.user-row').dataset.userId)));$$('.user-toggle').forEach(b=>b.addEventListener('click',()=>toggleUser(b.closest('.user-row').dataset.userId,b.textContent==='Aktivieren')))}catch(e){showError('#settings-error',e)}}
function openPassword(id){$('#password-user-id').value=id;$('#reset-password').value='';hideError('#password-error');$('#password-dialog').showModal()}
async function toggleUser(id,active){try{await api(`/api/admin/users/${id}`,{method:'PATCH',body:JSON.stringify({active})});await loadUsers();toast(active?'Benutzer aktiviert.':'Benutzer deaktiviert.')}catch(e){showError('#settings-error',e)}}
async function createUser(ev){ev.preventDefault();hideError('#user-error');const body={username:$('#new-username').value,displayName:$('#new-display-name').value,password:$('#new-password').value,role:$('#new-role').value};try{await api('/api/admin/users',{method:'POST',body:JSON.stringify(body)});$('#user-dialog').close();ev.currentTarget.reset();await loadUsers();toast('Benutzer angelegt.')}catch(e){showError('#user-error',e)}}
async function resetPassword(ev){ev.preventDefault();hideError('#password-error');try{await api(`/api/admin/users/${$('#password-user-id').value}/password`,{method:'POST',body:JSON.stringify({password:$('#reset-password').value})});$('#password-dialog').close();toast('Passwort zurückgesetzt.')}catch(e){showError('#password-error',e)}}
function dateInputValue(d) { return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}`; }
function localDayStartMS(value) {
if (!value) return 0;
const [y,m,d]=value.split('-').map(Number);
return new Date(y,m-1,d,0,0,0,0).getTime();
}
function exportParams(includePresentation=true) {
const p=new URLSearchParams();
const scope=$('input[name="export-scope"]:checked')?.value||'view';
if(scope==='view') {
const r=rangeForFilter();
if(state.filter.q) p.set('q',state.filter.q);
if(r.from) p.set('from',r.from);
if(r.to) p.set('to',r.to);
} else {
const from=localDayStartMS($('#export-from').value);
const toStart=localDayStartMS($('#export-to').value);
if(from) p.set('from',from);
if(toStart) { const end=new Date(toStart); end.setDate(end.getDate()+1); p.set('to',end.getTime()); }
}
if(includePresentation) {
if($('#export-sort').value==='asc') p.set('sort','asc');
if($('#export-compact').checked) p.set('compact','1');
}
return p;
}
let exportPreviewSeq=0;
async function updateExportPreview() {
const seq=++exportPreviewSeq;
const scope=$('input[name="export-scope"]:checked')?.value||'view';
$('#export-custom').hidden=scope!=='custom';
if(scope==='view') { $('#export-preview').textContent=`${state.totalCount} Einträge · ${duration(state.totalDuration)}`; return; }
const from=localDayStartMS($('#export-from').value), to=localDayStartMS($('#export-to').value);
if(!from||!to||to(e.client||'').trim()).filter(Boolean))];
if(!client&&visible.length===1) client=visible[0];
if(!client&&state.filter.q){const exact=state.clients.find(x=>x.toLowerCase()===state.filter.q.toLowerCase());if(exact)client=exact;}
$('#service-client').value=client;
if(!$('#service-date').value) $('#service-date').value=dateInputValue(new Date());
$('#export-dialog').close();
$('#service-report-dialog').showModal();
updateServicePreview();
}
async function downloadServiceReport(ev){
ev.preventDefault();hideError('#service-error');
const submit=$('#service-report-form button[type="submit"]');submit.disabled=true;
const body={...serviceFilterPayload(),client:$('#service-client').value.trim(),contact:$('#service-contact').value.trim(),location:$('#service-location').value.trim(),order_number:$('#service-order').value.trim(),subject:$('#service-subject').value.trim(),notes:$('#service-notes').value.trim(),place:$('#service-place').value.trim(),report_date:$('#service-date').value};
try{
const res=await fetch('/api/service-report.pdf',{method:'POST',headers:{'Content-Type':'application/json','X-CSRF-Token':state.csrf},body:JSON.stringify(body)});
if(res.status===401){location.assign('/login');return;}
if(!res.ok){const ct=res.headers.get('content-type')||'';const x=ct.includes('application/json')?await res.json().catch(()=>({})):await res.text();throw new Error(x?.error?.message||x||`HTTP ${res.status}`);}
const blob=await res.blob(),url=URL.createObjectURL(blob),a=document.createElement('a');
a.href=url;a.download='service-bericht.pdf';document.body.appendChild(a);a.click();a.remove();setTimeout(()=>URL.revokeObjectURL(url),1000);
$('#service-report-dialog').close();toast('Service-Bericht erstellt.');
}catch(e){showError('#service-error',e);}finally{submit.disabled=false;}
}
async function logout() {
if(!confirm('Abmelden?')) return;
try { await api('/api/logout',{method:'POST',body:'{}'}); } finally { location.assign('/login'); }
}
function wireEvents(){
$('#timer-button').addEventListener('click',timerToggle); $('#activity-input').addEventListener('blur',()=>saveRunningActivity().catch(e=>toast(e.message)));
$('#edit-running').addEventListener('click',()=>openEntry(null,true)); $('#add-entry').addEventListener('click',()=>openEntry());
$('#entry-form').addEventListener('submit',saveEntry); $('#delete-entry').addEventListener('click',deleteEntry); $('#edit-start').addEventListener('input',updateEditDuration); $('#edit-end').addEventListener('input',updateEditDuration);
$('#settings-open').addEventListener('click',openSettings); $('#settings-form').addEventListener('submit',saveSettings); $('#change-own-password').addEventListener('click',()=>{hideError('#account-password-error');$('#account-password-form').reset();$('#account-password-dialog').showModal()}); $('#account-password-form').addEventListener('submit',changeOwnPassword); $('#add-user').addEventListener('click',()=>{hideError('#user-error');$('#user-dialog').showModal()}); $('#user-form').addEventListener('submit',createUser); $('#password-form').addEventListener('submit',resetPassword);
$('#export-open').addEventListener('click',openExport); $('#history-export').addEventListener('click',openExport); $('#export-pdf').addEventListener('click',()=>downloadExport('pdf')); $('#export-csv').addEventListener('click',()=>downloadExport('csv')); $('#export-service').addEventListener('click',openServiceReport); $('#service-report-form').addEventListener('submit',downloadServiceReport); let serviceClientTimer; $('#service-client').addEventListener('input',()=>{clearTimeout(serviceClientTimer);serviceClientTimer=setTimeout(updateServicePreview,220)}); $$('input[name="export-scope"]').forEach(x=>x.addEventListener('change',updateExportPreview)); $('#export-from').addEventListener('change',updateExportPreview); $('#export-to').addEventListener('change',updateExportPreview);
$('#account-menu').addEventListener('click',logout); $('#mobile-logout').addEventListener('click',logout);
let searchTimer; $('#search-input').addEventListener('input',e=>{clearTimeout(searchTimer);searchTimer=setTimeout(()=>{state.filter.q=e.target.value.trim();state.filter.offset=0;refreshEntries(true)},220)});
$$('.period-tabs button').forEach(b=>b.addEventListener('click',()=>{$$('.period-tabs button').forEach(x=>x.classList.remove('active'));b.classList.add('active');state.filter.period=b.dataset.period;state.filter.anchor=new Date();state.filter.offset=0;refreshEntries(true)}));
$('#period-prev').addEventListener('click',()=>stepPeriod(-1)); $('#period-next').addEventListener('click',()=>stepPeriod(1));
$('#load-more').addEventListener('click',()=>{state.filter.offset=state.entries.length;refreshEntries(false)});
$$('[data-close]').forEach(b=>b.addEventListener('click',()=>document.getElementById(b.dataset.close).close()));
$$('dialog').forEach(d=>d.addEventListener('click',e=>{const r=d.getBoundingClientRect();if(e.clientXr.right||e.clientYr.bottom)d.close()}));
$('#mobile-history').addEventListener('click',()=>switchMobileView('history')); $('#mobile-track').addEventListener('click',()=>switchMobileView('track')); $('#mobile-nav-track').addEventListener('click',()=>switchMobileView('track')); $('#mobile-nav-history').addEventListener('click',()=>switchMobileView('history')); $('#mobile-nav-settings').addEventListener('click',openSettings);
}
wireEvents(); init();