/* Human support: explicit submit only. Do not serialize the SDK or application state. */ (()=>{ 'use strict'; if(window.CateriumSupportForm)return; const EMAIL='support@caterium.ru',ENDPOINT=new URL('../api/support.php',document.currentScript.src).href; const identity=()=>`${window.SunCloudV2?.getSession?.()?.user?.id||''}:${window.SunCloudV2?.getWorkspace?.()?.id||''}`; let root,form,tab,csrf='',busy=false,controller=null,scope=identity(),generation=0,lastPayload='',requestId=''; const $=id=>root?.querySelector('#'+id); const uuid=()=>typeof crypto.randomUUID==='function'?crypto.randomUUID():[4,2,2,2,6].map(n=>Array.from(crypto.getRandomValues(new Uint8Array(n)),v=>v.toString(16).padStart(2,'0')).join('')).join('-'); function status(message,error=false){$('ctContactStatus').textContent=message;$('ctContactStatus').setAttribute('role',error?'alert':'status');$('ctContactStatus').classList.toggle('ct-contact-error',error);} function show(){ if(!root)return; $('ctHelpGuide').hidden=true;$('ctHelpSupport').hidden=true;$('ctContactSection').hidden=false; $('ctHelpGuideTab').setAttribute('aria-pressed','false');$('ctHelpSupportTab').setAttribute('aria-pressed','false');tab.setAttribute('aria-pressed','true'); root.querySelector('.ct-help-content').scrollTop=0; const user=window.SunCloudV2?.getSession?.()?.user; if(!form.dataset.prefilled){$('ctContactEmail').value=typeof user?.email==='string'?user.email:'';$('ctContactName').value=typeof user?.user_metadata?.name==='string'?user.user_metadata.name:'';form.dataset.prefilled='1';} $('ctContactName').focus({preventScroll:true}); } async function request(options={}){ const activeController=new AbortController();controller=activeController;const timer=setTimeout(()=>activeController.abort(),20000); try{ const response=await fetch(ENDPOINT,{credentials:'same-origin',cache:'no-store',signal:activeController.signal,...options}); let value;try{value=await response.json();}catch(_){throw new Error('Сервер не подтвердил отправку. Текст остаётся в форме.');} if(!response.ok){if(response.status===403)csrf='';throw new Error(typeof value.message==='string'?value.message:'Не удалось отправить сообщение.');} return value; }finally{clearTimeout(timer);if(controller===activeController)controller=null;} } async function send(event){ event.preventDefault();if(busy||!form.reportValidity())return; const ticket=generation,who=identity();busy=true;form.setAttribute('aria-busy','true'); const payload={name:$('ctContactName').value.trim(),email:$('ctContactEmail').value.trim(),topic:$('ctContactTopic').value,subject:$('ctContactSubject').value.trim(),message:$('ctContactMessage').value.trim(),website:$('ctContactWebsite').value}; if($('ctContactDiagnostics').checked){ payload.device=String(navigator.userAgent).slice(0,600)+`; экран ${innerWidth} × ${innerHeight}`; payload.section=String(document.querySelector('header nav button.on')?.textContent||'Вход').trim().slice(0,100); payload.release=String(window.SunPerformance?.VERSION||'').slice(0,60); } const fingerprint=JSON.stringify(payload);if(fingerprint!==lastPayload||!requestId){lastPayload=fingerprint;requestId=uuid();} status('Отправляю обращение…');form.querySelectorAll('input,textarea,select,button').forEach(e=>e.disabled=true); try{ if(!csrf){const setup=await request();if(typeof setup.csrf!=='string'||setup.recipient!==EMAIL)throw new Error('Не удалось подготовить защищённую отправку.');csrf=setup.csrf;} if(ticket!==generation||who!==identity())return; const answer=await request({method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({...payload,csrf,request_id:requestId})}); if(ticket!==generation||who!==identity())return; if(answer.ok!==true||answer.status!=='accepted'||!/^SUP-[0-9]{8}-[A-F0-9]{12}$/.test(answer.id||''))throw new Error('Результат отправки не подтверждён. Текст остаётся в форме.'); status(`Обращение ${answer.id} принято почтовым сервером для отправки на ${EMAIL}. Ответ поддержки придёт на ${payload.email}.`); $('ctContactMessage').value='';$('ctContactSubject').value='';lastPayload='';requestId=''; }catch(error){ if(ticket===generation&&who===identity())status(error.name==='AbortError'?'Не удалось дождаться подтверждения. Текст сохранён в форме. Повторная отправка этого же сообщения не создаст дубликат в течение 48 часов.':String(error.message||'Не удалось отправить сообщение.'),true); }finally{ if(ticket===generation){busy=false;form.setAttribute('aria-busy','false');form.querySelectorAll('input,textarea,select,button').forEach(e=>e.disabled=false);} } } function attach(dialog){ if(root===dialog)return; root=dialog;scope=identity(); const style=document.createElement('style');style.textContent=` #ctHelpDialog .ct-help-modes{flex-wrap:wrap}#ctHelpDialog #ctContactTab{font-weight:700} #ctHelpDialog .ct-contact-cta{padding:16px;border:1px solid #d1c49d;border-radius:12px;background:#f8f4e7;margin:18px 0} #ctHelpDialog .ct-contact-cta p{margin:0 0 10px}#ctHelpDialog .ct-contact-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px} #ctHelpDialog .ct-contact-wide{grid-column:1/-1}#ctHelpDialog #ctContactForm textarea{font:16px/1.5 Arial,sans-serif;resize:vertical;width:100%;min-height:150px;padding:12px;border:1px solid #cdd5cb;border-radius:10px;background:#fff;color:#263d31} #ctHelpDialog #ctContactForm textarea:focus-visible{outline:3px solid #b39b47;outline-offset:2px}#ctHelpDialog .ct-contact-check{display:flex;flex-direction:row;align-items:flex-start;font-size:13px;gap:8px} #ctHelpDialog .ct-contact-check input{width:18px;height:18px;min-height:18px;flex:0 0 18px;margin:2px 0 0} #ctHelpDialog .ct-contact-note{font-size:12px;color:#617166}#ctHelpDialog #ctContactSend{background:#304f3d;color:#fff;justify-self:start} #ctHelpDialog [disabled]{cursor:wait;opacity:.65}#ctHelpDialog .ct-contact-error{color:#9e3028}#ctHelpDialog #ctContactStatus:empty{display:none} #ctHelpDialog .ct-contact-hp{position:absolute;left:-10000px;width:1px;height:1px;overflow:hidden}#ctHelpDialog #ctContactStatus{overflow-wrap:anywhere} @media(max-width:600px){#ctHelpDialog .ct-contact-grid{grid-template-columns:minmax(0,1fr)}#ctHelpDialog #ctContactSend{width:100%}} `;document.head.append(style); tab=document.createElement('button');tab.id='ctContactTab';tab.type='button';tab.textContent='Написать в поддержку';tab.setAttribute('aria-pressed','false');root.querySelector('.ct-help-modes').append(tab);tab.onclick=show; const section=document.createElement('section');section.id='ctContactSection';section.hidden=true; section.innerHTML=`

Не нашли ответ или возникла проблема?

Опишите вопрос — обращение будет направлено на ${EMAIL}. Для ответа укажите свою почту.

Не указывайте пароли, коды подтверждения, секретные ключи и лишние персональные данные. При нажатии «Отправить» имя, email и сообщение передаются службе поддержки. Форма не открывает почтовое приложение.

Если отправка через форму недоступна, напишите напрямую: ${EMAIL}.

`; root.querySelector('.ct-help-content').append(section);form=$('ctContactForm');form.addEventListener('submit',send); for(const id of ['ctHelpGuide','ctHelpSupport']){ const cta=document.createElement('div');cta.className='ct-contact-cta';cta.innerHTML='

Не нашли ответ? Мы поможем разобраться.

'; $(id).append(cta);cta.querySelector('button').onclick=show; } root.addEventListener('click',event=>{if(event.target.closest('#ctHelpGuideTab,#ctHelpSupportTab')){section.hidden=true;tab.setAttribute('aria-pressed','false');}}); } function resetIfChanged(){ const next=identity();if(next===scope)return;scope=next;generation++;controller?.abort();csrf='';lastPayload='';requestId='';busy=false; if(form){form.reset();delete form.dataset.prefilled;form.setAttribute('aria-busy','false');form.querySelectorAll('[disabled]').forEach(e=>e.disabled=false);status('');} } window.addEventListener('sun:cloud-permissions-changed',resetIfChanged); window.addEventListener('sun:cloud-tenant-changing',()=>{scope='';resetIfChanged();}); window.CateriumSupportForm=Object.freeze({attach}); const existing=document.getElementById('ctHelpDialog');if(existing)attach(existing); })();