(()=>{ 'use strict'; const VERSION='17.9.1-public-basic-signup'; const PENDING_REGISTRATION_KEY='sunPendingRegistrationV23'; let busy=false; const $=id=>document.getElementById(id); const cloud=()=>window.SunCloudV2||null; const client=()=>cloud()?.getClient?.()||null; const esc=value=>window.SunSafe?.escapeHTML?window.SunSafe.escapeHTML(String(value??'')):String(value??''); const PLAN_LABELS={basic:'Базовый',professional:'Профессиональный',full:'Полный'}; let signupPolicy={checked:false,promoOptional:false,defaultPlan:'basic'}; async function refreshSignupPolicy(c=client()){ if(!c)return signupPolicy; try{ const {data,error}=await c.rpc('caterium_public_signup_policy'); if(error)throw error; signupPolicy={checked:true,promoOptional:data?.promo_optional===true,defaultPlan:data?.default_plan==='basic'?'basic':'basic'}; }catch(_){signupPolicy={checked:true,promoOptional:false,defaultPlan:'basic'};} return signupPolicy; } function promoHintText(){return signupPolicy.promoOptional?'Без промокода будет создана компания на Базовом тарифе. Промокод может активировать другой тариф и пробный период.':'Для создания новой компании требуется действующий промокод.';} function renderPromoPolicy(){const label=$('sunGatePromoLabelTextV181'),hint=$('sunGatePromoHintV181');if(label)label.textContent=signupPolicy.promoOptional?'Промокод — необязательно':'Промокод пробной версии';if(hint&&!String($('sunGatePromoV181')?.value||'').trim())hint.textContent=promoHintText();} function redirectUrl(){try{const u=new URL(location.href);u.hash='';return u.toString();}catch(_){return location.href.split('#')[0];}} function savePendingRegistration(email,promoCode){try{localStorage.setItem(PENDING_REGISTRATION_KEY,JSON.stringify({email:String(email||'').trim().toLowerCase(),companyName:'Новая компания',promoCode:String(promoCode||'').trim().toUpperCase(),createdAt:new Date().toISOString()}));}catch(_){}} function pendingRegistration(){try{return JSON.parse(localStorage.getItem(PENDING_REGISTRATION_KEY)||'null')}catch(_){return null}} function clearPendingRegistration(){try{localStorage.removeItem(PENDING_REGISTRATION_KEY)}catch(_){}} function setError(root,message){const node=root?.querySelector?.('#sunGateErrorV3');if(node)node.textContent=String(message||'');} function friendlySignupError(error){const message=String(error?.message||error||'Не удалось создать аккаунт.');if(/email address not authorized/i.test(message))return 'Не удалось отправить письмо подтверждения. Обратитесь к администратору Caterium.';if(/rate limit|rate_limit|too many/i.test(message))return 'Слишком много попыток регистрации. Попробуйте немного позже.';return message;} async function signOutUnsafeSession(c){try{await c?.auth?.signOut?.()}catch(_){}} function ensureRegistrationFields(){ const fields=$('sunGateRegisterFieldsV27');if(!fields)return; const company=$('sunGateCompanyV3');if(company?.parentElement)company.parentElement.remove(); if(!$('sunGatePromoV181')){ const label=document.createElement('label');label.id='sunGatePromoLabelV181';label.innerHTML='Промокод пробной версииПроверяю условия регистрации…'; fields.appendChild(label); const input=$('sunGatePromoV181');input?.addEventListener('input',()=>{input.value=input.value.toUpperCase().replace(/\s+/g,'');if(!input.value)renderPromoPolicy();}); input?.addEventListener('blur',async()=>{const code=String(input.value||'').trim(),email=String($('sunGateEmailV3')?.value||'').trim().toLowerCase(),h=$('sunGatePromoHintV181');if(!h)return;if(!code){await refreshSignupPolicy();renderPromoPolicy();return;}try{const c=client();if(!c)return;const {data,error}=await c.rpc('caterium_trial_promo_preview',{p_code:code,p_email:email||null});if(error)throw error;const label=PLAN_LABELS[data?.plan]||data?.plan||'тариф по промокоду';h.textContent=data?.valid?`Промокод принят · ${label} · ${Number(data.trial_days||14)} дней`:(data?.reason||'Промокод недействителен');}catch(_){h.textContent='Не удалось проверить промокод.';}}); } void refreshSignupPolicy().then(renderPromoPolicy); } async function validatePromo(c,email,code){ if(!code){const policy=await refreshSignupPolicy(c);if(policy.promoOptional)return {valid:true,plan:'basic',withoutPromo:true};throw new Error('Введите промокод пробной версии Caterium.');} const {data,error}=await c.rpc('caterium_trial_promo_preview',{p_code:code,p_email:email});if(error)throw error;if(!data?.valid)throw new Error(data?.reason||'Промокод недействителен.');return data; } function showPublicConfirmation(gate,email){if(!gate)return;gate.innerHTML=`
Caterium

Подтвердите email

Регистрация Caterium

Мы отправили письмо на ${esc(email)}. После подтверждения войдите в Caterium — компания и доступ будут созданы автоматически. Без промокода активируется Базовый тариф; с промокодом — тариф и срок по условиям кода. Название компании вы укажете в настройках.

`;gate.querySelector('#sunAuthGoLoginV1774')?.addEventListener('click',()=>location.reload(),{once:true});} function showInviteConfirmation(gate,email){if(!gate)return;gate.innerHTML=`
Caterium

Подтвердите email

Приглашение сохранено

Письмо подтверждения отправлено на ${esc(email)}. После подтверждения войдите по ссылке приглашения — Caterium автоматически подключит вас к компании.

`;gate.querySelector('#sunInviteReloadV1774')?.addEventListener('click',()=>location.reload(),{once:true});} async function publicLogin(gate){ if(busy)return;const c=client();if(!c){setError(gate,'Облачный сервис не подключён.');return;} const email=String($('sunGateEmailV3')?.value||'').trim().toLowerCase(),password=String($('sunGatePasswordV3')?.value||''); if(!email||password.length<6){setError(gate,'Введите email и пароль минимум из 6 символов.');return;} busy=true;const button=$('sunGateSubmitV3');if(button)button.disabled=true;setError(gate,'Выполняю вход…'); try{ const result=await c.auth.signInWithPassword({email,password});if(result.error)throw result.error; const persisted=await c.auth.getSession();if(persisted.error)throw persisted.error;if(!persisted.data?.session?.user)throw new Error('Сессия входа не сохранилась. Повторите вход.'); setError(gate,'Вход выполнен. Открываю Caterium…'); setTimeout(()=>location.reload(),120); }catch(error){setError(gate,window.CateriumCloudTransport?.errorMessage(error)||String(error?.message||error||'Не удалось войти.'));if(button)button.disabled=false;busy=false;} } async function publicSignup(gate){ if(busy)return;const c=client();if(!c){setError(gate,'Облачный сервис не подключён.');return;} const email=String($('sunGateEmailV3')?.value||'').trim().toLowerCase(),password=String($('sunGatePasswordV3')?.value||''),password2=String($('sunGatePassword2V27')?.value||''),promoCode=String($('sunGatePromoV181')?.value||'').trim().toUpperCase(); if(!email||password.length<6){setError(gate,'Введите email и пароль минимум из 6 символов.');return;}if(password!==password2){setError(gate,'Пароли не совпадают.');return;} busy=true;const button=$('sunGateSubmitV3');if(button)button.disabled=true;setError(gate,promoCode?'Проверяю промокод…':'Проверяю Базовый тариф…'); try{ await validatePromo(c,email,promoCode);savePendingRegistration(email,promoCode);setError(gate,'Создаю аккаунт…'); const existing=await c.auth.signInWithPassword({email,password});if(!existing.error&&existing.data?.session){location.reload();return;} const signupData=promoCode?{promo_code:promoCode}:{}; const result=await c.auth.signUp({email,password,options:{emailRedirectTo:redirectUrl(),data:signupData}});if(result.error)throw result.error; if(result.data?.session){await signOutUnsafeSession(c);throw new Error('Подтверждение email не включено на сервере. Регистрация остановлена.');} showPublicConfirmation(gate,email); }catch(error){clearPendingRegistration();setError(gate,friendlySignupError(error));if(button)button.disabled=false;}finally{busy=false;} } async function acceptInviteAfterLogin(token){const ws=await cloud()?.acceptInvite?.(token);if(!ws)throw new Error('Не удалось присоединиться к компании.');try{const u=new URL(location.href);u.searchParams.delete('invite');history.replaceState(null,'',u.toString())}catch(_){}location.reload();} async function inviteSignup(gate){ if(busy)return;const c=client();if(!c){setError(gate,'Облачный сервис не подключён.');return;} const email=String($('sunInviteEmailV27')?.value||'').trim().toLowerCase(),name=String($('sunInviteNameV27')?.value||'').trim(),password=String($('sunInvitePasswordV27')?.value||''),password2=String($('sunInvitePassword2V27')?.value||'');let token='';try{token=String(new URL(location.href).searchParams.get('invite')||'').trim()}catch(_){} if(!token){setError(gate,'Ссылка приглашения повреждена.');return;}if(!email||password.length<6){setError(gate,'Пароль должен содержать минимум 6 символов.');return;}if(password!==password2){setError(gate,'Пароли не совпадают.');return;} busy=true;const button=$('sunInviteJoinV27');if(button)button.disabled=true;setError(gate,'Проверяю аккаунт…'); try{const existing=await c.auth.signInWithPassword({email,password});if(!existing.error&&existing.data?.session){await acceptInviteAfterLogin(token);return;}const result=await c.auth.signUp({email,password,options:{emailRedirectTo:redirectUrl(),data:{name}}});if(result.error)throw result.error;if(result.data?.session){await signOutUnsafeSession(c);throw new Error('Подтверждение email не включено на сервере.');}showInviteConfirmation(gate,email);}catch(error){setError(gate,friendlySignupError(error));if(button)button.disabled=false;}finally{busy=false;} } async function finishOwnerOnboarding(gate){ if(busy)return false;const c=client(),api=cloud(),pending=pendingRegistration();if(!c||!api||!pending?.email)return false; const session=api.getSession?.();const email=String(session?.user?.email||'').trim().toLowerCase();if(!email||email!==String(pending.email||'').toLowerCase())return false; busy=true;setError(gate,'Подключаю рабочую базу…'); try{ const user=session.user;const metadata={...(user.user_metadata||{}),promo_code:pending.promoCode||null}; const updated=await c.auth.updateUser({data:metadata});if(updated.error)throw updated.error; const created=await c.rpc('sun_create_workspace',{p_name:'Новая компания'});if(created.error)throw created.error; clearPendingRegistration();await api.reloadMemberships?.();location.reload();return true; }catch(error){setError(gate,friendlySignupError(error));return false;}finally{busy=false;} } function neutralizeLegacyCompanyUI(){ const gate=$('sunCloudAuthGateV3');if(!gate)return; ensureRegistrationFields(); const recovery=$('sunGateRecoveryCompanyV25'); if(recovery){ recovery.closest('label')?.remove(); const button=$('sunGateRetryWorkspaceV3');if(button){button.textContent='Проверить доступ';button.onclick=async()=>{setError(gate,'Проверяю доступ…');try{const found=await cloud()?.reloadMemberships?.();if(found){location.reload();return;}if(await finishOwnerOnboarding(gate))return;await refreshSignupPolicy();setError(gate,signupPolicy.promoOptional?'Аккаунт не привязан к компании. Если вы сотрудник — попросите владельца добавить вас в «Пользователи и права». Для новой компании зарегистрируйтесь: без промокода доступен Базовый тариф.':'Аккаунт не привязан к компании. Если вы сотрудник — попросите владельца добавить вас в «Пользователи и права». Для новой компании нужен действующий промокод.');}catch(e){setError(gate,e?.message||String(e));}};} const title=gate.querySelector('h2');if(title)title.textContent='Нет доступа к компании'; const hints=gate.querySelectorAll('.hint');if(hints[1])hints[1].textContent='Этот аккаунт пока не привязан к рабочей компании.'; } gate.querySelectorAll('#sunCloudCreateWorkspaceV2,[data-create]').forEach(el=>el.remove()); } function publicRegistrationMode(){const fields=$('sunGateRegisterFieldsV27');return Boolean(fields&&!fields.hidden);} document.addEventListener('click',event=>{const target=event.target instanceof Element?event.target:null;if(!target)return;if(target.closest('#sunGateSubmitV3')){event.preventDefault();event.stopImmediatePropagation();if(publicRegistrationMode())publicSignup($('sunCloudAuthGateV3')).catch(error=>setError($('sunCloudAuthGateV3'),friendlySignupError(error)));else publicLogin($('sunCloudAuthGateV3')).catch(error=>setError($('sunCloudAuthGateV3'),String(error?.message||error||'Не удалось войти.')));return;}if(target.closest('#sunInviteJoinV27')){event.preventDefault();event.stopImmediatePropagation();inviteSignup($('sunCloudAuthGateV3')).catch(error=>setError($('sunCloudAuthGateV3'),friendlySignupError(error)));}},true); document.addEventListener('keydown',event=>{if(event.key!=='Enter')return;const target=event.target instanceof Element?event.target:null;if(target?.id==='sunGatePasswordV3'&&!publicRegistrationMode()){event.preventDefault();event.stopImmediatePropagation();publicLogin($('sunCloudAuthGateV3')).catch(error=>setError($('sunCloudAuthGateV3'),String(error?.message||error||'Не удалось войти.')));}else if(target?.id==='sunGatePassword2V27'&&publicRegistrationMode()){event.preventDefault();event.stopImmediatePropagation();publicSignup($('sunCloudAuthGateV3')).catch(error=>setError($('sunCloudAuthGateV3'),friendlySignupError(error)));}else if(target?.id==='sunInvitePassword2V27'){event.preventDefault();event.stopImmediatePropagation();inviteSignup($('sunCloudAuthGateV3')).catch(error=>setError($('sunCloudAuthGateV3'),friendlySignupError(error)));}},true); const observer=new MutationObserver(()=>neutralizeLegacyCompanyUI());observer.observe(document.documentElement,{childList:true,subtree:true}); const init=()=>{neutralizeLegacyCompanyUI();setTimeout(()=>{const gate=$('sunCloudAuthGateV3');if(gate&&pendingRegistration())finishOwnerOnboarding(gate);},500)}; if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',init,{once:true});else init(); window.CateriumAuthSecurityV1774=Object.freeze({VERSION,redirectUrl,ensureRegistrationFields}); })();