caterium-app/public/core/account-center-v1780.js
2026-09-12 10:10:25 +03:00

152 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(()=>{
'use strict';
if(window.CateriumAccountCenterV1780)return;
const VERSION='17.8.0-account-center-v3';
const $=(s,r=document)=>r.querySelector(s);
const qa=(s,r=document)=>[...r.querySelectorAll(s)];
const esc=v=>window.SunSafe?.escapeHTML?window.SunSafe.escapeHTML(String(v??'')):String(v??'');
const cloud=()=>window.SunCloudV2||null;
const client=()=>cloud()?.getClient?.()||null;
const workspace=()=>cloud()?.getWorkspace?.()||null;
const session=()=>cloud()?.getSession?.()||null;
const toast=(text,type='info',ms=4500)=>{try{return window.SunEnterprise?.toast?.(text,type,ms)}catch(_){console.log('[AccountCenter]',text)}};
const ROLE_LABELS={admin:'Владелец',manager:'Менеджер',kitchen:'Кухня',courier:'Курьер',viewer:'Просмотр'};
let snapshot=null;
let modal=null;
let lastUserId='';
function installStyle(){
if($('#caterium-account-center-style'))return;
const s=document.createElement('style');s.id='caterium-account-center-style';s.textContent=`
#cateriumAccountCenter{position:fixed;inset:0;z-index:21000;display:none;place-items:center;padding:22px;background:#102c3d99;backdrop-filter:blur(5px)}
#cateriumAccountCenter.on{display:grid}
#cateriumAccountCenter .cac-shell{width:min(980px,100%);max-height:min(860px,92vh);overflow:auto;background:#f6f2ea;border-radius:22px;box-shadow:0 28px 90px #0004;color:#2f2b25}
#cateriumAccountCenter .cac-head{display:flex;justify-content:space-between;gap:16px;align-items:flex-start;padding:28px 30px 20px;border-bottom:1px solid #d9d1c5}
#cateriumAccountCenter h2{margin:0;font:500 38px/1.04 Georgia,'Times New Roman',serif;letter-spacing:-.03em;color:#27231f}
#cateriumAccountCenter .cac-sub{margin-top:7px;color:#8a8379;font-size:14px}
#cateriumAccountCenter .cac-close{border:0;background:transparent;font-size:31px;color:#5c564d;padding:0 4px}
#cateriumAccountCenter .cac-body{padding:24px 30px 30px}
#cateriumAccountCenter .cac-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}
#cateriumAccountCenter .cac-card{background:#fffaf2;border:1px solid #ddd4c7;border-radius:16px;padding:20px}
#cateriumAccountCenter .cac-card.wide{grid-column:1/-1}
#cateriumAccountCenter .cac-card h3{margin:0 0 14px;color:#302b25;font-size:17px}
#cateriumAccountCenter .cac-meta{display:grid;gap:8px;margin:0 0 16px}.cac-meta div{display:flex;justify-content:space-between;gap:20px;padding-bottom:8px;border-bottom:1px dashed #e3dbcf}.cac-meta span{color:#8c857b}.cac-meta b{color:#332f29;text-align:right}
#cateriumAccountCenter label{display:flex;flex-direction:column;gap:6px;margin:11px 0;color:#777066;font-size:12px;font-weight:700}
#cateriumAccountCenter input{min-height:48px;border:1px solid #cfc6ba;border-radius:11px;background:#fff;padding:0 13px;color:#2e2a25;font-size:15px;outline:none}
#cateriumAccountCenter input:focus{border-color:#d0a13c;box-shadow:0 0 0 4px rgba(208,161,60,.11)}
#cateriumAccountCenter .cac-actions{display:flex;gap:9px;flex-wrap:wrap;margin-top:14px}
#cateriumAccountCenter button.primary{border:0;border-radius:11px;background:linear-gradient(100deg,#d9aa42,#efca69);color:#171512;padding:12px 16px;font-weight:900}
#cateriumAccountCenter button.outline{border:1px solid #c9c1b6;border-radius:11px;background:#fffaf2;color:#37332d;padding:11px 15px;font-weight:800}
#cateriumAccountCenter .cac-note{font-size:12px;color:#8a8379;line-height:1.55;margin-top:9px}
#cateriumAccountCenter .cac-owner{display:flex;align-items:center;gap:10px;padding:11px 13px;background:#fbf2d9;border:1px solid #ead39a;border-radius:12px;margin-bottom:12px}.cac-owner b{display:block;color:#725317}.cac-owner span{color:#8a6e36;font-size:12px}
#cateriumAccountCenter .cac-company-actions{display:flex;gap:10px;flex-wrap:wrap}
#sunCurrentUserLabel{cursor:pointer}
#sunCurrentUserLabel:hover{text-decoration:underline;text-underline-offset:3px}
#cateriumAccountButton{display:flex!important}
#sun-cloud-users-modal [data-caterium-owner-row="1"]{background:#fff9e8;border:1px solid #ead39a;border-radius:10px;padding:10px}
#sun-cloud-users-modal .caterium-owner-chip{display:inline-flex;align-items:center;border-radius:999px;background:#f4dfad;color:#6d5118;padding:5px 9px;font-size:11px;font-weight:900}
@media(max-width:720px){#cateriumAccountCenter{padding:0;place-items:stretch}#cateriumAccountCenter .cac-shell{width:100%;max-height:none;height:100dvh;border-radius:0}#cateriumAccountCenter .cac-grid{grid-template-columns:1fr}#cateriumAccountCenter .cac-card.wide{grid-column:auto}#cateriumAccountCenter .cac-head,#cateriumAccountCenter .cac-body{padding-left:18px;padding-right:18px}}
`;document.head.appendChild(s);
}
function ensureModal(){
if(modal)return modal;
modal=document.createElement('div');modal.id='cateriumAccountCenter';modal.innerHTML='<div class="cac-shell"><div class="cac-head"><div><h2>Мой аккаунт</h2><div class="cac-sub">Профиль и безопасность Caterium</div></div><button class="cac-close" type="button" aria-label="Закрыть">×</button></div><div class="cac-body" id="cateriumAccountCenterBody"></div></div>';
document.body.appendChild(modal);
modal.addEventListener('click',e=>{if(e.target===modal||e.target.closest('.cac-close'))close();});
return modal;
}
async function loadSnapshot(){
const c=client(),ws=workspace();if(!c||!ws?.id)return null;
const {data,error}=await c.rpc('caterium_account_snapshot',{p_workspace:ws.id});
if(error)throw error;snapshot=data||null;return snapshot;
}
function render(){
const body=$('#cateriumAccountCenterBody');if(!body)return;
const ss=session(),s=snapshot||{},owner=Boolean(s.is_owner);
const companyNo=s.company_number?`${s.company_number}`:'—';
body.innerHTML=`<div class="cac-grid">
<section class="cac-card">
<h3>Профиль</h3>
${owner?'<div class="cac-owner"><div><b>Главный аккаунт компании</b><span>Только этот аккаунт создаёт сотрудников и распределяет права.</span></div></div>':''}
<div class="cac-meta"><div><span>Компания</span><b>${esc(s.company_name||'—')} · ${esc(companyNo)}</b></div><div><span>Статус</span><b>${esc(owner?'Владелец':ROLE_LABELS[s.role]||s.role||'Сотрудник')}</b></div></div>
<label>Имя<input id="cacName" value="${esc(s.display_name||ss?.user?.user_metadata?.name||'')}"></label>
<div class="cac-actions"><button class="primary" id="cacSaveName" type="button">Сохранить имя</button></div>
</section>
<section class="cac-card">
<h3>Email для входа</h3>
<label>Текущий email<input value="${esc(ss?.user?.email||s.email||'')}" disabled></label>
<label>Новый email<input id="cacEmail" type="email" autocomplete="email" placeholder="new@email.com"></label>
<div class="cac-actions"><button class="primary" id="cacSaveEmail" type="button">Изменить email</button></div>
<div class="cac-note">На новый адрес придёт письмо подтверждения.</div>
</section>
<section class="cac-card">
<h3>Смена пароля</h3>
<label>Новый пароль<input id="cacPassword" type="password" autocomplete="new-password" minlength="8"></label>
<label>Повторите пароль<input id="cacPassword2" type="password" autocomplete="new-password" minlength="8"></label>
<div class="cac-actions"><button class="primary" id="cacSavePassword" type="button">Сменить пароль</button></div>
<div class="cac-note">Пароль меняется только для вашего аккаунта. Администратор компании его не видит.</div>
</section>
${owner?`<section class="cac-card"><h3>Компания и пользователи</h3><p class="cac-note">Создавайте сотрудников, назначайте им рабочую роль и включайте только нужные права.</p><div class="cac-company-actions"><button class="primary" id="cacOpenUsers" type="button">Пользователи и права</button></div></section>`:''}
<section class="cac-card wide"><h3>Сеанс</h3><div class="cac-actions"><button class="outline" id="cacLogout" type="button">Выйти из аккаунта</button></div></section>
</div>`;
$('#cacSaveName').onclick=saveName;$('#cacSaveEmail').onclick=saveEmail;$('#cacSavePassword').onclick=savePassword;$('#cacLogout').onclick=logout;
const users=$('#cacOpenUsers');if(users)users.onclick=()=>{close();window.SunAdminRBACV3?.openUsers?.();setTimeout(sanitizeRbac,100);};
}
async function saveName(){
const name=String($('#cacName')?.value||'').trim();if(!name)return toast('Введите имя.','warn');
const c=client();if(!c)return;const btn=$('#cacSaveName');btn.disabled=true;
try{const {data,error}=await c.rpc('caterium_update_my_name',{p_display_name:name});if(error)throw error;const r=await c.auth.updateUser({data:{name:data||name}});if(r.error)throw r.error;await cloud()?.reloadMemberships?.();await loadSnapshot();render();window.SunAdminRBACV3?.apply?.();toast('Имя изменено.','success');}
catch(e){toast(e?.message||String(e),'error',6500)}finally{btn.disabled=false}
}
async function saveEmail(){
const email=String($('#cacEmail')?.value||'').trim().toLowerCase();if(!email)return toast('Введите новый email.','warn');
const c=client();if(!c)return;const btn=$('#cacSaveEmail');btn.disabled=true;
try{const {error}=await c.auth.updateUser({email});if(error)throw error;$('#cacEmail').value='';toast('На новый email отправлено письмо подтверждения.','success',6500)}catch(e){toast(e?.message||String(e),'error',6500)}finally{btn.disabled=false}
}
async function savePassword(){
const p=String($('#cacPassword')?.value||''),p2=String($('#cacPassword2')?.value||'');
if(p.length<8)return toast('Пароль должен быть не короче 8 символов.','warn');if(p!==p2)return toast('Пароли не совпадают.','warn');
const c=client();if(!c)return;const btn=$('#cacSavePassword');btn.disabled=true;
try{const {error}=await c.auth.updateUser({password:p});if(error)throw error;$('#cacPassword').value='';$('#cacPassword2').value='';toast('Пароль изменён.','success')}
catch(e){toast(e?.message||String(e),'error',6500)}finally{btn.disabled=false}
}
async function logout(){try{await cloud()?.signOut?.()}catch(_){try{await client()?.auth.signOut()}catch(__){}location.reload()}}
async function open(){
ensureModal();modal.classList.add('on');const body=$('#cateriumAccountCenterBody');body.innerHTML='<p class="cac-note">Загружаю аккаунт…</p>';
try{await loadSnapshot();render()}catch(e){body.innerHTML=`<p class="cac-note">${esc(e?.message||e||'Не удалось загрузить аккаунт.')}</p>`}
}
function close(){modal?.classList.remove('on')}
function sanitizeRbac(){
const body=$('#sunRbacBody');if(!body)return;
qa('select option[value="admin"]',body).forEach(o=>o.remove());
qa('[data-rbac-perm="users.manage"]',body).forEach(i=>{i.checked=false;i.disabled=true;const row=i.closest('label');if(row)row.title='Это право принадлежит только главному аккаунту компании';});
if(snapshot?.is_owner&&snapshot?.user_id){
const btn=body.querySelector(`[data-rbac-edit="${CSS.escape(String(snapshot.user_id))}"]`);
if(btn){const row=btn.closest('.sun-rbac-member');if(row){row.dataset.cateriumOwnerRow='1';const role=row.querySelector('.role-chip');if(role)role.textContent='Владелец';btn.outerHTML='<span class="caterium-owner-chip">Главный аккаунт</span>';}}
}
const addRole=$('#sunRbacEmployeeRole',body);if(addRole)qa('option[value="admin"]',addRole).forEach(o=>o.remove());
}
function ensureSidebarEntry(){
const footer=$('.sun-side-footer');if(!footer||!session()?.user)return;
let button=$('#cateriumAccountButton');
if(!button){
button=document.createElement('button');
button.id='cateriumAccountButton';button.type='button';button.className='sun-side-action';button.title='Профиль, email и пароль';
button.innerHTML='<span>◎</span><span>Мой аккаунт</span>';
footer.insertBefore(button,footer.querySelector('#sunLogoutBtn')||footer.firstChild);
}
if(!button.dataset.cateriumAccountBound){button.dataset.cateriumAccountBound='1';button.addEventListener('click',open)}
}
function bindEntry(){
const label=$('#sunCurrentUserLabel');if(label&&!label.dataset.cateriumAccountBound){label.dataset.cateriumAccountBound='1';label.title='Открыть личный кабинет';label.addEventListener('click',open)}
const ss=session();const uid=ss?.user?.id||'';if(uid&&uid!==lastUserId){lastUserId=uid;snapshot=null;}
ensureSidebarEntry();sanitizeRbac();
}
installStyle();ensureModal();bindEntry();
const obs=new MutationObserver(bindEntry);obs.observe(document.documentElement,{childList:true,subtree:true});
window.addEventListener('sun:cloud-permissions-changed',()=>setTimeout(bindEntry,0));
setInterval(()=>{if(!document.hidden)bindEntry()},3000);
window.CateriumAccountCenterV1780=Object.freeze({VERSION,open,close,reload:async()=>{await loadSnapshot();render();return snapshot}});
})();