const SETTINGS_API='./api/index.php'; const settingsCtx={csrf:'',user:null,data:null}; const settingsPages=['Overview','Offices','Vendors','Purchases','Assets','Inventory','Issue & transfers','Reports','Users & access','Settings']; const settingsActions=[['office_create','Create offices'],['office_edit','Edit offices'],['vendor_create','Create vendors'],['vendor_edit','Edit vendors'],['category_create','Create categories'],['category_edit','Edit categories'],['category_delete','Delete categories'],['asset_create','Create assets'],['asset_edit','Edit assets'],['purchase_create','Create purchases'],['stock_create','Create inventory items'],['stock_edit','Edit inventory items'],['movement_create','Issue / transfer / return'],['record_status','Activate / deactivate records'],['record_delete','Delete unlinked records']]; const roleDefaults={admin:{pages:settingsPages,actions:settingsActions.map(x=>x[0])},store:{pages:['Overview','Vendors','Purchases','Assets','Inventory','Issue & transfers','Reports'],actions:['vendor_create','vendor_edit','asset_create','asset_edit','purchase_create','stock_create','stock_edit','movement_create']},office:{pages:['Overview','Assets','Issue & transfers'],actions:[]}}; const settingsEsc=v=>String(v??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); const settingsActive=r=>Number(r?.active)!==0; const settingsPage=()=>document.querySelector('.breadcrumb strong')?.textContent.trim()||''; async function settingsApi(action,data){const r=await fetch(`${SETTINGS_API}?action=${action}`,{method:data?'POST':'GET',credentials:'same-origin',headers:data?{'Content-Type':'application/json','X-CSRF-Token':settingsCtx.csrf}:undefined,body:data?JSON.stringify(data):undefined});const j=await r.json().catch(()=>({error:'Server returned an invalid response.'}));if(j.csrf)settingsCtx.csrf=j.csrf;if(!r.ok)throw Error(j.error||'Request failed');return j;} async function settingsLoad(){const s=await settingsApi('session');settingsCtx.user=s.user;if(!settingsCtx.user||settingsCtx.user.role!=='admin')return false;settingsCtx.data=(await settingsApi('data')).data;applyBusinessBranding(settingsCtx.data.settings);return true;} function applyBusinessBranding(settings){const s=settings||{};const name=s.business_name?.trim()||'AssetDesk';const brand=document.querySelector('.brand');if(brand&&brand.firstChild)brand.firstChild.nodeValue=name;const workspace=document.querySelector('.workspace > div');if(workspace&&workspace.firstChild)workspace.firstChild.nodeValue=name;document.title=`${name} — Office Asset Management`;const icon=document.querySelector('.brand-icon');if(icon&&s.logo){icon.innerHTML=`${settingsEsc(name)} logo`;icon.classList.add('has-business-logo');}} function normalizedPermissions(user){let p=user?.permissions;if(typeof p==='string'){try{p=JSON.parse(p)}catch{p=null}}if(!p||typeof p!=='object')p=roleDefaults[user?.role]||roleDefaults.office;return {pages:Array.isArray(p.pages)?p.pages:[],actions:Array.isArray(p.actions)?p.actions:[]};} function checkedOptions(options,selected,kind){return options.map(item=>{const key=Array.isArray(item)?item[0]:item;const label=Array.isArray(item)?item[1]:item;return ``}).join('');} function settingsPanelMarkup(){return `
ADMINISTRATION CENTER

Business & access settings

Apne business ki identity, users, roles aur form access yahan manage karein.

ADMIN ONLY

Business profile

Yeh naam dashboard, sidebar aur browser title par show hoga.

Logo preview

Logo optional hai. Save karne ke baad sidebar aur dashboard branding update ho jayegi.

User accounts & permissions

Har user ke liye role, visible pages aur create/edit/delete rights define karein.

USERROLEOFFICESTATUSACCESSACTIONS

Role guide

Role defaults apply jab user ke liye custom permissions select na ki jayein.

AdministratorComplete business, user, record aur settings access.
Store operatorPurchases, vendors, assets, inventory aur movements.
Office viewerAssigned office ke records read-only mode mein.
`;} function officeName(id){return (settingsCtx.data?.offices||[]).find(o=>Number(o.id)===Number(id))?.name||'All offices';} function renderUsers(panel){const body=panel.querySelector('[data-users-body]');const users=settingsCtx.data?.users||[];body.innerHTML=users.length?users.map(u=>{const p=normalizedPermissions(u);return `${settingsEsc(u.name)}${settingsEsc(u.email)}${settingsEsc(u.role)}${settingsEsc(officeName(u.office_id))}${settingsActive(u)?'Active':'Inactive'}${p.pages.length} pages · ${p.actions.length} rights
`}).join(''):'No users found. Create the first user above.';} function setBusinessForm(panel){const s=settingsCtx.data?.settings||{};const form=panel.querySelector('.business-form');for(const key of ['business_name','business_phone','business_email','business_address']){const input=form.elements[key];if(input)input.value=s[key]||'';}const preview=panel.querySelector('[data-logo-preview]');if(s.logo){preview.innerHTML=`Current business logo`}else preview.innerHTML='No logo selected';} function openUserEditor(user){const editing=!!user;const initialRole=user?.role||'store';const perms=normalizedPermissions(user||{role:initialRole});const offices=(settingsCtx.data?.offices||[]).filter(settingsActive);const root=document.createElement('div');root.className='settings-user-backdrop';root.innerHTML=``;document.body.append(root);const modal=root.firstElementChild;const form=modal.querySelector('form');const close=()=>root.remove();modal.querySelector('.settings-modal-close').onclick=close;modal.querySelector('.settings-modal-cancel').onclick=close;root.addEventListener('click',e=>{if(e.target===root)close()});const role=form.elements.role;const office=form.elements.office_id;const syncOffice=()=>{const isOffice=role.value==='office';modal.querySelector('[data-office-field]').hidden=!isOffice;office.required=isOffice;if(!isOffice)office.value='';};const setChecks=(name,values)=>modal.querySelectorAll(`input[name="${name}"]`).forEach(input=>input.checked=values.includes(input.value));const applyDefaults=()=>{const d=roleDefaults[role.value]||roleDefaults.store;setChecks('pages',d.pages);setChecks('actions',d.actions);};form.elements.name.value=user?.name||'';form.elements.email.value=user?.email||'';role.value=initialRole;if(editing){form.elements.active.value=settingsActive(user)?'1':'0';office.value=user.office_id||'';}role.onchange=syncOffice;modal.querySelector('[data-apply-role-defaults]').onclick=applyDefaults;syncOffice();form.onsubmit=async e=>{e.preventDefault();const button=form.querySelector('button[type="submit"]');const message=modal.querySelector('[data-user-message]');button.disabled=true;message.textContent='';const payload={name:form.elements.name.value,email:form.elements.email.value,role:role.value,office_id:office.value,permissions:JSON.stringify({pages:[...modal.querySelectorAll('input[name="pages"]:checked')].map(x=>x.value),actions:[...modal.querySelectorAll('input[name="actions"]:checked')].map(x=>x.value)})};if(editing){payload.id=user.id;payload.active=form.elements.active.value;}else payload.password=form.elements.password.value;try{await settingsApi(editing?'user_update':'user',payload);close();await refreshSettings();}catch(err){message.textContent=err.message;button.disabled=false;}};} async function resetUser(user){const password=window.prompt('New password (minimum 12 characters)');if(password===null)return;if(password.length<12){window.alert('Password minimum 12 characters ka hona chahiye.');return;}try{await settingsApi('reset',{id:user.id,password});await refreshSettings();window.alert('Password reset ho gaya.');}catch(e){window.alert(e.message);}} async function userAction(panel,e){const button=e.target.closest('[data-user-action]');if(!button)return;const user=(settingsCtx.data?.users||[]).find(u=>String(u.id)===button.dataset.id);if(!user)return;try{const action=button.dataset.userAction;if(action==='edit'){openUserEditor(user);return}if(action==='reset'){await resetUser(user);return}if(action==='toggle'){const next=!settingsActive(user);if(!window.confirm(`${next?'Activate':'Deactivate'} this user?`))return;await settingsApi('set_active',{entity:'user',id:user.id,active:next?'1':'0'});}if(action==='delete'){if(!window.confirm('Delete this user permanently? Linked history will block deletion.'))return;await settingsApi('delete_record',{entity:'user',id:user.id});}await refreshSettings();}catch(err){window.alert(err.message);}} async function readLogo(file){if(!file)return settingsCtx.data?.settings?.logo||'';if(file.size>800000)throw Error('Logo file 800 KB se choti honi chahiye.');return new Promise((resolve,reject)=>{const reader=new FileReader();reader.onload=()=>resolve(reader.result);reader.onerror=()=>reject(Error('Logo read nahi ho saka.'));reader.readAsDataURL(file);});} function wireBusiness(panel){const form=panel.querySelector('.business-form');form.onsubmit=async e=>{e.preventDefault();const button=form.querySelector('button[type="submit"]');const message=panel.querySelector('[data-business-message]');button.disabled=true;message.textContent='';try{const file=form.elements.logo_file.files[0];const payload={business_name:form.elements.business_name.value,business_phone:form.elements.business_phone.value,business_email:form.elements.business_email.value,business_address:form.elements.business_address.value,logo:await readLogo(file)};await settingsApi('settings_update',payload);await refreshSettings();message.textContent='Business profile save ho gaya.';}catch(err){message.textContent=err.message}finally{button.disabled=false;}};} async function refreshSettings(){if(!(await settingsLoad()))return;const old=document.querySelector('[data-settings-panel]');if(old){const fresh=document.createElement('div');fresh.innerHTML=settingsPanelMarkup();const panel=fresh.firstElementChild;old.replaceWith(panel);renderUsers(panel);setBusinessForm(panel);wireBusiness(panel);}} function enhanceSettings(){if(!settingsCtx.user||settingsCtx.user.role!=='admin'||settingsPage()!=='Settings')return;let panel=document.querySelector('[data-settings-panel]');if(!panel){const old=document.querySelector('section.settings');if(!old)return;const holder=document.createElement('div');holder.innerHTML=settingsPanelMarkup();panel=holder.firstElementChild;old.replaceWith(panel);renderUsers(panel);setBusinessForm(panel);wireBusiness(panel);}if(panel&&!panel.dataset.settingsEvents){panel.dataset.settingsEvents='1';panel.querySelector('[data-add-user]').onclick=()=>openUserEditor(null);panel.addEventListener('click',e=>userAction(panel,e));}} const settingsObserver=new MutationObserver(()=>requestAnimationFrame(enhanceSettings));settingsObserver.observe(document.body,{childList:true,subtree:true}); setInterval(async()=>{if(!settingsCtx.user){if(await settingsLoad())enhanceSettings();}else{applyBusinessBranding(settingsCtx.data?.settings);enhanceSettings();}},1500); settingsLoad().then(enhanceSettings).catch(()=>{});