a605c92ab3
- Modal on login page: Name, Email, Phone with client-side validation - POST /request-access → sends Telegram message via corporate proxy - Includes IP + geo lookup (ip-api.com) - Success screen after submission, Esc/click-outside closes modal Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
234 lines
10 KiB
HTML
234 lines
10 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="ru">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title>Вход — WBfeed</title>
|
|
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}" />
|
|
</head>
|
|
<body>
|
|
<div class="login-split">
|
|
|
|
<!-- Левая панель — маркетинг -->
|
|
<div class="login-promo">
|
|
<div class="login-promo__inner">
|
|
<div class="login-brand">
|
|
<div class="login-brand__icon">
|
|
<img src="{{ url_for('static', filename='wb3.png') }}" alt="WB">
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<h1 class="login-promo__title">Автоответы на отзывы<br>Wildberries — на автопилоте</h1>
|
|
<p class="login-promo__sub">Сервис сам отвечает на отзывы покупателей пока вы занимаетесь бизнесом. Никаких ручных ответов, никаких пропущенных оценок.</p>
|
|
|
|
<ul class="login-features">
|
|
<li class="login-features__item">
|
|
<span class="login-features__icon">⚡</span>
|
|
<div>
|
|
<strong>Автоответы 24/7</strong>
|
|
<span>Настраивайте ответы для каждого рейтинга — от 1★ до 5★, с нужными шаблонами</span>
|
|
</div>
|
|
</li>
|
|
<li class="login-features__item">
|
|
<span class="login-features__icon">✏️</span>
|
|
<div>
|
|
<strong>Свои шаблоны</strong>
|
|
<span>Настройте уникальные ответы для каждой оценки — звучит как живой человек</span>
|
|
</div>
|
|
</li>
|
|
<li class="login-features__item">
|
|
<span class="login-features__icon">🏪</span>
|
|
<div>
|
|
<strong>Несколько магазинов</strong>
|
|
<span>Управляйте всеми аккаунтами WB из одного кабинета</span>
|
|
</div>
|
|
</li>
|
|
<li class="login-features__item">
|
|
<span class="login-features__icon">📋</span>
|
|
<div>
|
|
<strong>Журнал и очередь</strong>
|
|
<span>Видите каждый отправленный ответ с датой, оценкой и текстом</span>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
|
|
<div class="login-price">
|
|
<div class="login-price__amount">15 ₽<span>/день</span></div>
|
|
<div class="login-price__desc">За один магазин. До 144 ответов в день</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Правая панель — форма -->
|
|
<div class="login-form-wrap">
|
|
<section class="auth-card">
|
|
<div class="auth-kicker">
|
|
<img src="{{ url_for('static', filename='wb3.png') }}" class="auth-kicker-logo-img" alt="WB">
|
|
|
|
</div>
|
|
<h2 class="login-form-title">Войдите в кабинет</h2>
|
|
|
|
{% if error_message %}
|
|
<div class="alert alert-error">{{ error_message }}</div>
|
|
{% endif %}
|
|
|
|
<form method="post" class="auth-form">
|
|
<label>
|
|
Логин
|
|
<input type="text" name="username" placeholder="Введите логин" required autofocus />
|
|
</label>
|
|
<label>
|
|
Пароль
|
|
<input type="password" name="password" placeholder="••••••••" required />
|
|
</label>
|
|
<button type="submit">Войти</button>
|
|
</form>
|
|
|
|
<p class="auth-footer">Нет аккаунта? <a href="#" id="open-request-modal">Запросить доступ</a></p>
|
|
</section>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- Модал запроса доступа -->
|
|
<div class="modal-overlay" id="request-modal">
|
|
<div class="modal-card">
|
|
<button class="modal-close" id="close-request-modal">×</button>
|
|
|
|
<div id="modal-form-view">
|
|
<div class="auth-kicker" style="margin-bottom:16px">
|
|
<img src="{{ url_for('static', filename='wb3.png') }}" class="auth-kicker-logo-img" alt="WB">
|
|
</div>
|
|
<h2 class="login-form-title">Запросить доступ</h2>
|
|
<p style="font-size:13px;color:#6b7280;margin-bottom:20px;margin-top:-10px">Оставьте контакты — мы свяжемся и откроем доступ.</p>
|
|
|
|
<div class="alert alert-error" id="modal-error" style="display:none"></div>
|
|
|
|
<form class="auth-form" id="request-form" novalidate>
|
|
<label>
|
|
Имя
|
|
<input type="text" name="name" placeholder="Иван Иванов" required autocomplete="name">
|
|
<span class="field-error" id="err-name"></span>
|
|
</label>
|
|
<label>
|
|
Email
|
|
<input type="email" name="email" placeholder="ivan@company.ru" required autocomplete="email">
|
|
<span class="field-error" id="err-email"></span>
|
|
</label>
|
|
<label>
|
|
Телефон
|
|
<input type="tel" name="phone" placeholder="+7 999 000-00-00" required autocomplete="tel">
|
|
<span class="field-error" id="err-phone"></span>
|
|
</label>
|
|
<button type="submit" id="request-submit">Отправить запрос</button>
|
|
</form>
|
|
</div>
|
|
|
|
<div id="modal-success-view" style="display:none;text-align:center;padding:20px 0">
|
|
<div style="font-size:52px;margin-bottom:16px">✅</div>
|
|
<h2 style="margin-bottom:10px">Запрос отправлен!</h2>
|
|
<p style="font-size:14px;color:#6b7280">Мы получили ваши данные и скоро свяжемся с вами.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.modal-overlay {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: rgba(0,0,0,0.5);
|
|
backdrop-filter: blur(6px);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
z-index: 1000;
|
|
opacity: 0;
|
|
pointer-events: none;
|
|
transition: opacity 0.2s ease;
|
|
}
|
|
.modal-overlay.active { opacity: 1; pointer-events: all; }
|
|
.modal-card {
|
|
background: #fff;
|
|
border-radius: 22px;
|
|
padding: 40px;
|
|
width: 100%;
|
|
max-width: 420px;
|
|
margin: 20px;
|
|
position: relative;
|
|
box-shadow: 0 32px 80px rgba(0,0,0,0.22);
|
|
transform: translateY(20px) scale(0.98);
|
|
transition: transform 0.2s ease;
|
|
}
|
|
.modal-overlay.active .modal-card { transform: translateY(0) scale(1); }
|
|
.modal-close {
|
|
position: absolute;
|
|
top: 14px; right: 14px;
|
|
width: 32px; height: 32px;
|
|
border-radius: 50%;
|
|
background: #f3f4f6;
|
|
border: none;
|
|
font-size: 20px;
|
|
line-height: 1;
|
|
cursor: pointer;
|
|
color: #9ca3af;
|
|
display: flex; align-items: center; justify-content: center;
|
|
box-shadow: none; padding: 0;
|
|
}
|
|
.modal-close:hover { background: #e5e7eb; color: #374151; transform: none; filter: none; }
|
|
.field-error { display: block; font-size: 11px; color: #dc2626; margin-top: 3px; min-height: 15px; }
|
|
</style>
|
|
|
|
<script>
|
|
const modal = document.getElementById('request-modal');
|
|
const openBtn = document.getElementById('open-request-modal');
|
|
const closeBtn = document.getElementById('close-request-modal');
|
|
|
|
openBtn.addEventListener('click', e => { e.preventDefault(); modal.classList.add('active'); });
|
|
closeBtn.addEventListener('click', () => modal.classList.remove('active'));
|
|
modal.addEventListener('click', e => { if (e.target === modal) modal.classList.remove('active'); });
|
|
document.addEventListener('keydown', e => { if (e.key === 'Escape') modal.classList.remove('active'); });
|
|
|
|
document.getElementById('request-form').addEventListener('submit', async e => {
|
|
e.preventDefault();
|
|
const form = e.target;
|
|
const name = form.name.value.trim();
|
|
const email = form.email.value.trim();
|
|
const phone = form.phone.value.trim();
|
|
let valid = true;
|
|
|
|
['name','email','phone'].forEach(f => document.getElementById('err-' + f).textContent = '');
|
|
document.getElementById('modal-error').style.display = 'none';
|
|
|
|
if (!name)
|
|
{ document.getElementById('err-name').textContent = 'Введите имя'; valid = false; }
|
|
if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email))
|
|
{ document.getElementById('err-email').textContent = 'Введите корректный email'; valid = false; }
|
|
if (!phone || phone.replace(/\D/g, '').length < 10)
|
|
{ document.getElementById('err-phone').textContent = 'Введите корректный телефон'; valid = false; }
|
|
if (!valid) return;
|
|
|
|
const btn = document.getElementById('request-submit');
|
|
btn.disabled = true; btn.textContent = 'Отправка…';
|
|
|
|
try {
|
|
const res = await fetch('/request-access', { method: 'POST', body: new FormData(form) });
|
|
const data = await res.json();
|
|
if (data.ok) {
|
|
document.getElementById('modal-form-view').style.display = 'none';
|
|
document.getElementById('modal-success-view').style.display = 'block';
|
|
} else {
|
|
document.getElementById('modal-error').textContent = data.error || 'Ошибка. Попробуйте ещё раз.';
|
|
document.getElementById('modal-error').style.display = 'block';
|
|
btn.disabled = false; btn.textContent = 'Отправить запрос';
|
|
}
|
|
} catch {
|
|
document.getElementById('modal-error').textContent = 'Ошибка сети. Попробуйте ещё раз.';
|
|
document.getElementById('modal-error').style.display = 'block';
|
|
btn.disabled = false; btn.textContent = 'Отправить запрос';
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|