.
// Это происходит до того, как браузер успеет нарисовать ваш интерфейс.
const shield = document.createElement('style');
shield.id = 'auth-shield';
shield.innerHTML = 'body { visibility: hidden !important; }';
document.head.appendChild(shield);
// --- ШАГ 2: ВСЯ ОСТАЛЬНАЯ ЛОГИКА ---
// Теперь, пока пользователь видит гарантированно пустой экран, мы делаем все проверки.
// --- ГЛАВНЫЕ НАСТРОЙКИ ---
const SUPABASE_URL = 'https://votaafqxbldogbnoumwo.supabase.co';
const SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InZvdGFhZnF4Ymxkb2dibm91bXdvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDQ5NTUzMTksImV4cCI6MjA2MDUzMTMxOX0.OmuIO0hPBHlLgUWwIwv-qiWLrA-gmjL-Q5ajg0WzpB8';
const TABLE_NAME = '[КМ] - Статус клиента';
const LOGIN_COLUMN = 'login';
const PASSWORD_COLUMN = 'password';
const ID_KM_COLUMN = 'id_km';
const LOGO_URL = 'https://con.xl.ru/aZqKnTsoSEecd9bD0duIyA/images/rMAgdY48mku4a4Id59aKbQ.png';
const PERSISTENT_SESSION_KEY = 'auth_session_token';
const TEMP_SESSION_KEY = 'temp_auth_session';
const TEXTS = { 'ru': { title: 'SpeechFunnels', subtitle: 'Платформа для автоматизации экспертного контента и создания воронок продаж', loginPlaceholder: 'Введите ваш логин...', passwordPlaceholder: 'Введите ваш пароль...', rememberMeText: 'Запомнить меня на этом устройстве', buttonText: 'Войти', buttonLoadingText: 'Проверка...', errorText: 'Неверный логин или пароль' }, 'en': { title: 'SpeechFunnels', subtitle: 'A platform for creating and automating expert content and sales funnels.', loginPlaceholder: 'Enter your login...', passwordPlaceholder: 'Enter your password...', rememberMeText: 'Remember me on this device', buttonText: 'Login', buttonLoadingText: 'Checking...', errorText: 'Invalid login or password' } };
// --- Функция, которая "снимает щит" и плавно показывает страницу ---
const showPage = () => {
const shield = document.getElementById('auth-shield');
if (shield) {
shield.innerHTML = 'body { visibility: visible !important; opacity: 0; }';
setTimeout(() => {
const body = document.body;
body.style.transition = 'opacity 0.3s ease-in-out';
body.style.opacity = '1';
}, 50);
}
};
const initializeApp = async () => {
if (typeof supabase === 'undefined') { const script = document.createElement('script'); script.src = 'https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2'; document.head.appendChild(script); await new Promise(resolve => script.onload = resolve); }
const client = supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
const showFullScreenLockScreen = () => {
const container = document.getElementById('auth-container'); if (!container) { showPage(); return; }
const styles = `
.lock-screen-overlay { background-color: #0E2954; position: fixed; top: 0; left: 0; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; z-index: 2147483646; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } .lock-screen-content { background-color: rgba(255, 255, 255, 0.05); padding: 40px; border-radius: 20px; width: 90%; max-width: 450px; text-align: center; backdrop-filter: blur(10px); border: 1px solid rgba(255, 255, 255, 0.1); } .lock-screen-logo { width: 80px; height: 80px; margin-bottom: 20px; } .lock-screen-title { font-size: 32px; font-weight: 700; color: #FFFFFF; margin: 0; } .lock-screen-subtitle { font-size: 16px; color: rgba(255, 255, 255, 0.7); margin: 10px 0 30px; line-height: 1.5; } .lock-input-wrapper { position: relative; margin-bottom: 15px; } .lock-screen-input { width: 100%; padding: 15px 50px 15px 20px; font-size: 16px; border-radius: 10px; background-color: rgba(0, 0, 0, 0.2); border: 1px solid rgba(255, 255, 255, 0.2); color: #FFFFFF; box-sizing: border-box; outline: none; transition: all 0.2s; } #login-input { padding: 15px 20px; } .lock-screen-input::placeholder { color: rgba(255, 255, 255, 0.5); } .lock-screen-input:focus { border-color: #368dff; box-shadow: 0 0 0 4px rgba(54, 141, 255, 0.3); } .lock-password-toggle { position: absolute; top: 50%; right: 15px; transform: translateY(-50%); cursor: pointer; width: 24px; height: 24px; opacity: 0.6; transition: opacity 0.2s; } .lock-password-toggle:hover { opacity: 1; } .lock-screen-button { width: 100%; padding: 15px; font-size: 16px; font-weight: 600; color: #FFFFFF; background: linear-gradient(135deg, #368dff, #2563eb); border: none; border-radius: 10px; cursor: pointer; transition: transform 0.2s, box-shadow 0.2s; margin-top: 20px; } .lock-screen-button:hover { transform: translateY(-2px); box-shadow: 0 4px 15px rgba(0,0,0,0.2); } .lock-screen-button:disabled { background: #555; cursor: not-allowed; } .lock-lang-switcher { position: absolute; top: 20px; right: 20px; display: flex; gap: 5px; background: rgba(0,0,0,0.2); padding: 5px; border-radius: 8px; } .lock-lang-switcher button { background: none; border: none; color: rgba(255,255,255,0.5); font-size: 14px; font-weight: 600; padding: 5px 10px; cursor: pointer; border-radius: 6px; transition: all 0.2s; } .lock-lang-switcher button.active { background: rgba(255,255,255,0.2); color: #FFF; } .remember-me-wrapper { display: flex; align-items: center; justify-content: center; margin-top: 20px; cursor: pointer; } .remember-me-wrapper input { display: none; } .remember-me-checkbox { width: 20px; height: 20px; background: rgba(0,0,0,0.2); border: 1px solid rgba(255,255,255,0.2); border-radius: 6px; margin-right: 10px; display: flex; justify-content: center; align-items: center; transition: background-color 0.2s; } .remember-me-checkbox svg { display: none; } .remember-me-wrapper input:checked + .remember-me-checkbox { background-color: #368dff; } .remember-me-wrapper input:checked + .remember-me-checkbox svg { display: block; } .remember-me-label { color: rgba(255,255,255,0.8); font-size: 14px; } @keyframes shake { 10%, 90% { transform: translate3d(-1px, 0, 0); } 20%, 80% { transform: translate3d(2px, 0, 0); } 30%, 50%, 70% { transform: translate3d(-4px, 0, 0); } 40%, 60% { transform: translate3d(4px, 0, 0); } } .shake { animation: shake 0.82s cubic-bezier(.36,.07,.19,.97) both; }
`;
const styleSheet = document.createElement("style"); styleSheet.innerText = styles; document.head.appendChild(styleSheet);
const lockScreenHTML = `
`;
container.innerHTML = lockScreenHTML;
const contentBox = document.getElementById('lock-screen-content-box'), loginInput = document.getElementById('login-input'), passwordInput = document.getElementById('password-input'), confirmBtn = document.getElementById('confirm-btn'), togglePasswordBtn = document.getElementById('toggle-password'), rememberMeCheckbox = document.getElementById('remember-me-checkbox'); let currentLang = 'ru';
const eyeIcon = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%238892b0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z'%3E%3C/path%3E%3Ccircle cx='12' cy='12' r='3'%3E%3C/circle%3E%3C/svg%3E`;
const eyeOffIcon = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%238892b0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24'%3E%3C/path%3E%3Cline x1='1' y1='1' x2='23' y2='23'%3E%3C/line%3E%3C/svg%3E`;
togglePasswordBtn.src = eyeIcon;
const updateTexts = (lang) => { currentLang = lang; document.getElementById('lock-title').innerText = TEXTS[lang].title; document.getElementById('lock-subtitle').innerText = TEXTS[lang].subtitle; loginInput.placeholder = TEXTS[lang].loginPlaceholder; passwordInput.placeholder = TEXTS[lang].passwordPlaceholder; document.getElementById('remember-me-label').innerText = TEXTS[lang].rememberMeText; confirmBtn.innerText = TEXTS[lang].buttonText; document.getElementById('lang-ru').classList.toggle('active', lang === 'ru'); document.getElementById('lang-en').classList.toggle('active', lang === 'en'); };
confirmBtn.addEventListener('click', async () => { const login = loginInput.value.trim(), password = passwordInput.value.trim(); if (!login || !password) { contentBox.classList.add('shake'); setTimeout(() => contentBox.classList.remove('shake'), 820); return; }
confirmBtn.disabled = true; confirmBtn.innerText = TEXTS[currentLang].buttonLoadingText;
try { const { data, error } = await client.from(TABLE_NAME).select(ID_KM_COLUMN).eq(LOGIN_COLUMN, login).eq(PASSWORD_COLUMN, password).single(); if (error || !data) throw new Error('Invalid credentials');
const idKm = data[ID_KM_COLUMN]; if (rememberMeCheckbox.checked) { localStorage.setItem(PERSISTENT_SESSION_KEY, idKm); } else { sessionStorage.setItem(TEMP_SESSION_KEY, idKm); }
const currentUrl = new URL(window.location.href); currentUrl.searchParams.set('id_km', idKm); window.location.href = currentUrl.href;
} catch (err) { contentBox.classList.add('shake'); setTimeout(() => contentBox.classList.remove('shake'), 820); confirmBtn.innerText = TEXTS[currentLang].errorText; setTimeout(() => { confirmBtn.disabled = false; confirmBtn.innerText = TEXTS[currentLang].buttonText; }, 2000); }
});
togglePasswordBtn.addEventListener('click', () => { const isPassword = passwordInput.type === 'password'; passwordInput.type = isPassword ? 'text' : 'password'; togglePasswordBtn.src = isPassword ? eyeOffIcon : eyeIcon; });
document.getElementById('lang-ru').addEventListener('click', () => updateTexts('ru')); document.getElementById('lang-en').addEventListener('click', () => updateTexts('en')); updateTexts('ru');
showPage(); // Показываем экран входа
};
const checkAuth = async () => {
const persistentSession = localStorage.getItem(PERSISTENT_SESSION_KEY); const tempSession = sessionStorage.getItem(TEMP_SESSION_KEY); const idToVerify = persistentSession || tempSession;
if (!idToVerify) { showFullScreenLockScreen(); return; }
try {
const { error } = await client.from(TABLE_NAME).select(ID_KM_COLUMN).eq(ID_KM_COLUMN, idToVerify).single();
if (error) { localStorage.removeItem(PERSISTENT_SESSION_KEY); sessionStorage.removeItem(TEMP_SESSION_KEY); showFullScreenLockScreen(); return; }
const url = new URL(window.location.href); if (!url.searchParams.has('id_km')) { url.searchParams.set('id_km', idToVerify); window.location.href = url.href; return; }
showPage(); // Доступ разрешен, показываем интерфейс
} catch (err) { showFullScreenLockScreen(); }
};
checkAuth();
};
document.addEventListener('DOMContentLoaded', initializeApp);
})();
Страница авторизации в соцсетях