Allow Basic registration without promo code
This commit is contained in:
parent
10415fd539
commit
3d712eb19a
@ -1,7 +1,7 @@
|
|||||||
(()=>{
|
(()=>{
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const VERSION='17.8.5-single-session-login';
|
const VERSION='17.9.1-public-basic-signup';
|
||||||
const PENDING_REGISTRATION_KEY='sunPendingRegistrationV23';
|
const PENDING_REGISTRATION_KEY='sunPendingRegistrationV23';
|
||||||
let busy=false;
|
let busy=false;
|
||||||
|
|
||||||
@ -9,7 +9,20 @@
|
|||||||
const cloud=()=>window.SunCloudV2||null;
|
const cloud=()=>window.SunCloudV2||null;
|
||||||
const client=()=>cloud()?.getClient?.()||null;
|
const client=()=>cloud()?.getClient?.()||null;
|
||||||
const esc=value=>window.SunSafe?.escapeHTML?window.SunSafe.escapeHTML(String(value??'')):String(value??'');
|
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 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 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(_){}}
|
||||||
@ -23,16 +36,20 @@
|
|||||||
const fields=$('sunGateRegisterFieldsV27');if(!fields)return;
|
const fields=$('sunGateRegisterFieldsV27');if(!fields)return;
|
||||||
const company=$('sunGateCompanyV3');if(company?.parentElement)company.parentElement.remove();
|
const company=$('sunGateCompanyV3');if(company?.parentElement)company.parentElement.remove();
|
||||||
if(!$('sunGatePromoV181')){
|
if(!$('sunGatePromoV181')){
|
||||||
const label=document.createElement('label');label.id='sunGatePromoLabelV181';label.innerHTML='<span>Промокод пробной версии</span><input id="sunGatePromoV181" autocomplete="off" maxlength="32" placeholder="Например, CTM-A7K4P9"><small id="sunGatePromoHintV181" style="display:block;margin-top:5px;opacity:.72">Промокод создаёт компанию и активирует пробный период.</small>';
|
const label=document.createElement('label');label.id='sunGatePromoLabelV181';label.innerHTML='<span id="sunGatePromoLabelTextV181">Промокод пробной версии</span><input id="sunGatePromoV181" autocomplete="off" maxlength="32" placeholder="Например, CTM-A7K4P9"><small id="sunGatePromoHintV181" style="display:block;margin-top:5px;opacity:.72">Проверяю условия регистрации…</small>';
|
||||||
fields.appendChild(label);
|
fields.appendChild(label);
|
||||||
const input=$('sunGatePromoV181');input?.addEventListener('input',()=>{input.value=input.value.toUpperCase().replace(/\s+/g,'');});
|
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(!code||!h)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;h.textContent=data?.valid?`Промокод принят · ${Number(data.trial_days||14)} дней пробного доступа`:(data?.reason||'Промокод недействителен');}catch(_){h.textContent='Не удалось проверить промокод.';}});
|
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)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;}
|
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=`<div class="sun-cloud-auth-card"><div class="sun-cloud-auth-brand"><img src="caterium-login-logo.png" alt="Caterium"><div><h2>Подтвердите email</h2><div class="hint">Регистрация Caterium</div></div></div><p class="hint">Мы отправили письмо на <b>${esc(email)}</b>. После подтверждения войдите в Caterium — компания и пробный период будут созданы автоматически. Название компании вы укажете в настройках.</p><div class="sun-cloud-auth-actions"><button class="primary" id="sunAuthGoLoginV1774" type="button">Перейти ко входу</button></div></div>`;gate.querySelector('#sunAuthGoLoginV1774')?.addEventListener('click',()=>location.reload(),{once:true});}
|
function showPublicConfirmation(gate,email){if(!gate)return;gate.innerHTML=`<div class="sun-cloud-auth-card"><div class="sun-cloud-auth-brand"><img src="caterium-login-logo.png" alt="Caterium"><div><h2>Подтвердите email</h2><div class="hint">Регистрация Caterium</div></div></div><p class="hint">Мы отправили письмо на <b>${esc(email)}</b>. После подтверждения войдите в Caterium — компания и доступ будут созданы автоматически. Без промокода активируется Базовый тариф; с промокодом — тариф и срок по условиям кода. Название компании вы укажете в настройках.</p><div class="sun-cloud-auth-actions"><button class="primary" id="sunAuthGoLoginV1774" type="button">Перейти ко входу</button></div></div>`;gate.querySelector('#sunAuthGoLoginV1774')?.addEventListener('click',()=>location.reload(),{once:true});}
|
||||||
function showInviteConfirmation(gate,email){if(!gate)return;gate.innerHTML=`<div class="sun-cloud-auth-card"><div class="sun-cloud-auth-brand"><img src="caterium-login-logo.png" alt="Caterium"><div><h2>Подтвердите email</h2><div class="hint">Приглашение сохранено</div></div></div><p class="hint">Письмо подтверждения отправлено на <b>${esc(email)}</b>. После подтверждения войдите по ссылке приглашения — Caterium автоматически подключит вас к компании.</p><div class="sun-cloud-auth-actions"><button class="primary" id="sunInviteReloadV1774" type="button">Я подтвердил email</button></div></div>`;gate.querySelector('#sunInviteReloadV1774')?.addEventListener('click',()=>location.reload(),{once:true});}
|
function showInviteConfirmation(gate,email){if(!gate)return;gate.innerHTML=`<div class="sun-cloud-auth-card"><div class="sun-cloud-auth-brand"><img src="caterium-login-logo.png" alt="Caterium"><div><h2>Подтвердите email</h2><div class="hint">Приглашение сохранено</div></div></div><p class="hint">Письмо подтверждения отправлено на <b>${esc(email)}</b>. После подтверждения войдите по ссылке приглашения — Caterium автоматически подключит вас к компании.</p><div class="sun-cloud-auth-actions"><button class="primary" id="sunInviteReloadV1774" type="button">Я подтвердил email</button></div></div>`;gate.querySelector('#sunInviteReloadV1774')?.addEventListener('click',()=>location.reload(),{once:true});}
|
||||||
|
|
||||||
async function publicLogin(gate){
|
async function publicLogin(gate){
|
||||||
@ -53,11 +70,12 @@
|
|||||||
if(busy)return;const c=client();if(!c){setError(gate,'Облачный сервис не подключён.');return;}
|
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();
|
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;}
|
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,'Проверяю промокод…');
|
busy=true;const button=$('sunGateSubmitV3');if(button)button.disabled=true;setError(gate,promoCode?'Проверяю промокод…':'Проверяю Базовый тариф…');
|
||||||
try{
|
try{
|
||||||
await validatePromo(c,email,promoCode);savePendingRegistration(email,promoCode);setError(gate,'Создаю аккаунт…');
|
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 existing=await c.auth.signInWithPassword({email,password});if(!existing.error&&existing.data?.session){location.reload();return;}
|
||||||
const result=await c.auth.signUp({email,password,options:{emailRedirectTo:redirectUrl(),data:{promo_code:promoCode}}});if(result.error)throw result.error;
|
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 не включено на сервере. Регистрация остановлена.');}
|
if(result.data?.session){await signOutUnsafeSession(c);throw new Error('Подтверждение email не включено на сервере. Регистрация остановлена.');}
|
||||||
showPublicConfirmation(gate,email);
|
showPublicConfirmation(gate,email);
|
||||||
}catch(error){clearPendingRegistration();setError(gate,friendlySignupError(error));if(button)button.disabled=false;}finally{busy=false;}
|
}catch(error){clearPendingRegistration();setError(gate,friendlySignupError(error));if(button)button.disabled=false;}finally{busy=false;}
|
||||||
@ -73,11 +91,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function finishOwnerOnboarding(gate){
|
async function finishOwnerOnboarding(gate){
|
||||||
if(busy)return false;const c=client(),api=cloud(),pending=pendingRegistration();if(!c||!api||!pending?.promoCode)return false;
|
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;
|
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,'Подключаю рабочую базу…');
|
busy=true;setError(gate,'Подключаю рабочую базу…');
|
||||||
try{
|
try{
|
||||||
const user=session.user;const metadata={...(user.user_metadata||{}),promo_code:pending.promoCode};
|
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 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;
|
const created=await c.rpc('sun_create_workspace',{p_name:'Новая компания'});if(created.error)throw created.error;
|
||||||
clearPendingRegistration();await api.reloadMemberships?.();location.reload();return true;
|
clearPendingRegistration();await api.reloadMemberships?.();location.reload();return true;
|
||||||
@ -90,7 +108,7 @@
|
|||||||
const recovery=$('sunGateRecoveryCompanyV25');
|
const recovery=$('sunGateRecoveryCompanyV25');
|
||||||
if(recovery){
|
if(recovery){
|
||||||
recovery.closest('label')?.remove();
|
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;setError(gate,'Аккаунт не привязан к компании. Если вы сотрудник — попросите владельца добавить вас в «Пользователи и права». Для новой компании зарегистрируйте пробный период по промокоду.');}catch(e){setError(gate,e?.message||String(e));}};}
|
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 title=gate.querySelector('h2');if(title)title.textContent='Нет доступа к компании';
|
||||||
const hints=gate.querySelectorAll('.hint');if(hints[1])hints[1].textContent='Этот аккаунт пока не привязан к рабочей компании.';
|
const hints=gate.querySelectorAll('.hint');if(hints[1])hints[1].textContent='Этот аккаунт пока не привязан к рабочей компании.';
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user