const CATEGORY_API='./api/index.php'; const categoryCtx={csrf:'',user:null,data:null}; const categoryEsc=v=>String(v??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); const categoryActive=r=>Number(r?.active)!==0; const categoryPage=()=>document.querySelector('.breadcrumb strong')?.textContent.trim()||''; async function categoryApi(action,data){const r=await fetch(`${CATEGORY_API}?action=${action}`,{method:data?'POST':'GET',credentials:'same-origin',headers:data?{'Content-Type':'application/json','X-CSRF-Token':categoryCtx.csrf}:undefined,body:data?JSON.stringify(data):undefined});const j=await r.json().catch(()=>({error:'Server returned an invalid response.'}));if(j.csrf)categoryCtx.csrf=j.csrf;if(!r.ok)throw Error(j.error||'Request failed');return j;} async function categoryLoad(){const s=await categoryApi('session');categoryCtx.user=s.user;if(!categoryCtx.user||categoryCtx.user.role!=='admin')return false;categoryCtx.data=(await categoryApi('data')).data;return true;} function categoryRows(){return categoryCtx.data?.categories||[];} function fillCategorySelects(){const active=categoryRows().filter(categoryActive);const signature=active.map(c=>`${c.id}:${c.name}`).join('|');document.querySelectorAll('.modal .field select[name="category"]').forEach(select=>{if(select.dataset.categorySignature===signature)return;const current=select.value;select.innerHTML=''+active.map(c=>``).join('');if(active.some(c=>c.name===current))select.value=current;select.dataset.categorySignature=signature;});} function categoryButton(){if(!categoryCtx.user||categoryCtx.user.role!=='admin'||!['Assets','Purchases'].includes(categoryPage()))return;const host=document.querySelector('.page-heading > .heading-actions');if(!host||host.querySelector('[data-category-button]'))return;const button=document.createElement('button');button.type='button';button.className='secondary category-manage-button';button.dataset.categoryButton='1';button.textContent='Manage categories';button.onclick=openCategoryManager;host.append(button);} function categoryModalMarkup(){return `
`;} function renderCategoryRows(root){const list=root.querySelector('[data-category-list]');const rows=categoryRows();list.innerHTML=rows.length?rows.map(r=>`
${categoryEsc(r.name)}${categoryActive(r)?'Active':'Inactive'}
`).join(''):'
No categories yet. Add the first category above.
';} async function refreshCategoryModal(root){try{await categoryLoad();renderCategoryRows(root);fillCategorySelects();}catch(e){root.querySelector('.category-error').textContent=e.message;}} function openCategoryManager(){const root=document.createElement('div');root.innerHTML=categoryModalMarkup();document.body.append(root);const backdrop=root.firstElementChild;const close=()=>root.remove();backdrop.querySelector('.category-close').onclick=close;backdrop.addEventListener('click',e=>{if(e.target===backdrop)close()});backdrop.querySelector('.category-add-form').onsubmit=async e=>{e.preventDefault();const form=e.currentTarget;const button=form.querySelector('button');const error=backdrop.querySelector('.category-error');button.disabled=true;error.textContent='';try{await categoryApi('category',{name:new FormData(form).get('name')});form.reset();await refreshCategoryModal(backdrop)}catch(err){error.textContent=err.message}finally{button.disabled=false}};backdrop.addEventListener('click',async e=>{const button=e.target.closest('[data-category-action]');if(!button)return;const record=categoryRows().find(r=>String(r.id)===button.dataset.id);if(!record)return;const action=button.dataset.categoryAction;const error=backdrop.querySelector('.category-error');error.textContent='';try{if(action==='edit'){const name=window.prompt('Category name',record.name);if(name===null||!name.trim())return;await categoryApi('category_update',{id:record.id,name:name.trim()});}else if(action==='toggle'){const next=!categoryActive(record);if(!window.confirm(`Are you sure you want to ${next?'activate':'deactivate'} this category?`))return;await categoryApi('set_active',{entity:'category',id:record.id,active:next?'1':'0'});}else if(action==='delete'){if(!window.confirm('Delete this category permanently? Used categories must be deactivated instead.'))return;await categoryApi('category_delete',{id:record.id});}await refreshCategoryModal(backdrop);}catch(err){error.textContent=err.message;}});refreshCategoryModal(backdrop);} const categoryObserver=new MutationObserver(()=>requestAnimationFrame(()=>{categoryButton();fillCategorySelects();})); categoryObserver.observe(document.body,{childList:true,subtree:true}); setInterval(async()=>{if(!categoryCtx.user&&await categoryLoad())categoryButton();fillCategorySelects();},1500); categoryLoad().then(()=>{categoryButton();fillCategorySelects()}).catch(()=>{});