v2: личный кабинет — проверка заявки по email

This commit is contained in:
yerzhan_assanov2 2026-09-15 07:17:22 +00:00
parent c0fc6680e6
commit 45032d127d
3 changed files with 114 additions and 1 deletions

104
cabinet.html Normal file
View File

@ -0,0 +1,104 @@
<!DOCTYPE html>
<html lang="ru" data-theme="auto">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Мой кабинет — Хакатон Казахтелеком</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>👤</text></svg>">
<link rel="stylesheet" href="design-system/kt-ai-fonts.css">
<link rel="stylesheet" href="design-system/kt-ai-tokens.css">
<link rel="stylesheet" href="design-system/kt-ai-components.css">
<link rel="stylesheet" href="design-system/kt-ai-page.css">
<style>
a.kt-ai-btn { text-decoration: none; }
.check-form { max-width: 480px; margin: 0 auto; display: grid; gap: var(--kt-ai-space-4); }
.card-info { max-width: 560px; margin: var(--kt-ai-space-7) auto 0; display: grid; gap: var(--kt-ai-space-3); }
.info-row { display: flex; justify-content: space-between; gap: var(--kt-ai-space-4); padding: var(--kt-ai-space-2) 0; border-bottom: 1px solid var(--kt-ai-divider); font-size: var(--kt-ai-text-sm); }
.info-row:last-child { border-bottom: none; }
.info-row span:first-child { color: var(--kt-ai-fg-muted); }
.info-row span:last-child { text-align: right; font-weight: var(--kt-ai-weight-medium); }
.status-msg { max-width: 560px; margin: var(--kt-ai-space-7) auto 0; padding: var(--kt-ai-space-5); border-radius: var(--kt-ai-radius-lg); background: var(--kt-ai-bg-soft); border: 1px solid var(--kt-ai-border); }
.status-msg.err { border-color: var(--kt-ai-danger); color: var(--kt-ai-danger); }
</style>
</head>
<body>
<header class="kt-ai-pagehead">
<div class="kt-ai-wrap kt-ai-pagehead-in">
<strong>Хакатон Казахтелеком</strong>
<span class="kt-ai-spacer"></span>
<a class="kt-ai-btn" data-variant="ghost" href="index.html">Регистрация</a>
<a class="kt-ai-btn" data-variant="primary" href="admin.html">Список участников</a>
</div>
</header>
<section class="kt-ai-hero" data-align="center">
<div class="kt-ai-wrap">
<h1>Мой кабинет</h1>
<p class="kt-ai-hero-sub">Введи email, на который регистрировался — покажем твою заявку и её статус.</p>
</div>
</section>
<section class="kt-ai-section">
<div class="kt-ai-wrap">
<form id="checkForm" class="check-form">
<div class="kt-ai-field">
<label for="email">Email</label>
<input class="kt-ai-input" id="email" type="email" placeholder="you@example.kz" required>
</div>
<button class="kt-ai-btn" data-variant="primary" type="submit">Показать заявку</button>
</form>
<div id="result" hidden></div>
</div>
</section>
<footer class="kt-ai-wrap kt-ai-pagefoot">
<span>© 2026 АО «Казахтелеком» · Хакатон</span>
<span class="kt-ai-spacer"></span>
<a class="kt-ai-link" href="index.html">Регистрация</a>
</footer>
<script>
var form = document.getElementById("checkForm");
var result = document.getElementById("result");
function esc(s) { return String(s || "").replace(/[&<>"']/g, function (c) { return { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" }[c]; }); }
form.addEventListener("submit", async function (e) {
e.preventDefault();
result.hidden = true;
var email = form.email.value.trim();
try {
var resp = await fetch("api/status?email=" + encodeURIComponent(email));
var data = await resp.json();
if (!data.ok) throw new Error("Ошибка сервера");
if (!data.registration) {
result.className = "status-msg err";
result.innerHTML = "Заявки с email <b>" + esc(email) + "</b> не найдено. Проверь адрес или <a class='kt-ai-link' href='index.html'>зарегистрируйся</a>.";
} else {
var r = data.registration;
result.className = "status-msg";
result.innerHTML =
'<div style="display:flex;align-items:center;gap:var(--kt-ai-space-3);margin-bottom:var(--kt-ai-space-3)">' +
'<span class="kt-ai-chip">✅ Зарегистрирован</span>' +
'<span style="color:var(--kt-ai-fg-muted);font-size:var(--kt-ai-text-sm)">заявка от ' + esc((r.createdAt || "").slice(0, 10)) + '</span></div>' +
'<div class="info-row"><span>ФИО</span><span>' + esc(r.fio) + '</span></div>' +
'<div class="info-row"><span>Email</span><span>' + esc(r.email) + '</span></div>' +
'<div class="info-row"><span>Телефон</span><span>' + esc(r.phone) + '</span></div>' +
'<div class="info-row"><span>Город</span><span>' + esc(r.city) + '</span></div>' +
'<div class="info-row"><span>Направление</span><span>' + esc(r.track) + '</span></div>' +
'<div class="info-row"><span>Роль</span><span>' + esc(r.role) + '</span></div>' +
'<div class="info-row"><span>Команда</span><span>' + (r.team ? esc(r.team) : "—") + '</span></div>' +
'<div class="info-row"><span>Статус</span><span>Заявка принята, ждём тебя на хакатоне!</span></div>';
}
result.hidden = false;
} catch (err) {
result.className = "status-msg err";
result.textContent = "Не удалось проверить заявку: " + err.message;
result.hidden = false;
}
});
</script>
</body>
</html>

View File

@ -27,7 +27,7 @@
<div class="kt-ai-wrap kt-ai-pagehead-in"> <div class="kt-ai-wrap kt-ai-pagehead-in">
<strong>Хакатон Казахтелеком</strong> <strong>Хакатон Казахтелеком</strong>
<span class="kt-ai-spacer"></span> <span class="kt-ai-spacer"></span>
<a class="kt-ai-btn" data-variant="ghost" href="#about">О хакатоне</a> <a class="kt-ai-btn" data-variant="ghost" href="cabinet.html">Мой кабинет</a>
<a class="kt-ai-btn" data-variant="primary" href="#register">Зарегистрироваться</a> <a class="kt-ai-btn" data-variant="primary" href="#register">Зарегистрироваться</a>
</div> </div>
</header> </header>
@ -129,6 +129,7 @@
<footer class="kt-ai-wrap kt-ai-pagefoot"> <footer class="kt-ai-wrap kt-ai-pagefoot">
<span>© 2026 АО «Казахтелеком» · Хакатон</span> <span>© 2026 АО «Казахтелеком» · Хакатон</span>
<span class="kt-ai-spacer"></span> <span class="kt-ai-spacer"></span>
<a class="kt-ai-link" href="cabinet.html">Мой кабинет</a>
<a class="kt-ai-link" href="admin.html">Список участников</a> <a class="kt-ai-link" href="admin.html">Список участников</a>
</footer> </footer>

View File

@ -33,6 +33,14 @@ http.createServer(async (req, res) => {
return res.end(JSON.stringify(readItems())); return res.end(JSON.stringify(readItems()));
} }
if (req.method === "GET" && url === "/api/status") {
const q = new URL(req.url, "http://x").searchParams;
const email = (q.get("email") || "").trim().toLowerCase();
const found = readItems().find(i => i.email.toLowerCase() === email);
res.writeHead(200, { "Content-Type": "application/json" });
return res.end(JSON.stringify({ ok: true, registration: found || null }));
}
if (req.method === "POST" && url === "/api/register") { if (req.method === "POST" && url === "/api/register") {
const item = await body(req); const item = await body(req);
if (!item.fio || !item.email || !item.phone || !item.city || !item.track || !item.role || !item.experience) { if (!item.fio || !item.email || !item.phone || !item.city || !item.track || !item.role || !item.experience) {