diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..25006ea --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +.vibe42-run.log +.vibe42-run.pid diff --git a/data.json b/data.json new file mode 100644 index 0000000..200977b --- /dev/null +++ b/data.json @@ -0,0 +1,26 @@ +[ + { + "id": 1, + "firstName": "Алишер", + "lastName": "Нурсултанов", + "phone": "+7 (777) 123-45-67", + "telegram": "@alisher_ns", + "registeredAt": "2026-09-12T10:30:00.000Z" + }, + { + "id": 2, + "firstName": "Динара", + "lastName": "Кенжегулова", + "phone": "+7 (701) 234-56-78", + "telegram": "@dinara_kz", + "registeredAt": "2026-09-13T14:15:00.000Z" + }, + { + "id": 3, + "firstName": "Максат", + "lastName": "Ибрагимов", + "phone": "+7 (778) 345-67-89", + "telegram": "@maxat_dev", + "registeredAt": "2026-09-13T16:45:00.000Z" + } +] diff --git a/index.html b/index.html index b9535da..b4c873c 100644 --- a/index.html +++ b/index.html @@ -75,6 +75,14 @@ font-size: 48px; margin-bottom: var(--kt-ai-space-3); } + .error-message { + background: var(--kt-ai-bg-soft); + border: 1px solid var(--kt-ai-border); + border-radius: var(--kt-ai-radius-xl); + padding: var(--kt-ai-space-4); + color: var(--kt-ai-fg-muted); + margin-top: var(--kt-ai-space-4); + } @@ -100,7 +108,7 @@

Зарегистрироваться - Участники + О хакатоне
@@ -175,9 +183,10 @@

Регистрация успешна!

Добро пожаловать на Hackathon Open 2026!

+ -
+

📅 Когда

15-17 ноября 2026, старт в пятницу 18:00

@@ -199,8 +208,6 @@
- - diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..1bf705e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "hackathon-registration", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "hackathon-registration" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..80a471f --- /dev/null +++ b/package.json @@ -0,0 +1,6 @@ +{ + "name": "hackathon-registration", + "private": true, + "type": "commonjs", + "scripts": { "start": "node server.js" } +} diff --git a/server.js b/server.js new file mode 100644 index 0000000..1bba6d4 --- /dev/null +++ b/server.js @@ -0,0 +1,65 @@ +const http = require("http"); +const fs = require("fs"); +const path = require("path"); + +const PORT = process.env.PORT || 3000; +const DATA = path.join(__dirname, "data.json"); + +function readItems() { + try { return JSON.parse(fs.readFileSync(DATA, "utf8")); } catch (_) { return []; } +} +function writeItems(items) { + fs.writeFileSync(DATA, JSON.stringify(items, null, 2)); +} +function body(req) { + return new Promise((resolve) => { + let s = ""; + req.on("data", (c) => (s += c)); + req.on("end", () => { try { resolve(JSON.parse(s || "{}")); } catch (_) { resolve({}); } }); + }); +} + +http.createServer(async (req, res) => { + const urlPath = req.url.split("?")[0]; + + if (req.method === "GET" && urlPath === "/api/registrations") { + res.writeHead(200, { "Content-Type": "application/json" }); + return res.end(JSON.stringify(readItems())); + } + + if (req.method === "POST" && urlPath === "/api/registrations") { + const item = await body(req); + const items = readItems(); + const newItem = { + id: Date.now(), + firstName: item.firstName || "", + lastName: item.lastName || "", + phone: item.phone || "", + telegram: item.telegram || "", + registeredAt: new Date().toISOString() + }; + items.push(newItem); + writeItems(items); + res.writeHead(200, { "Content-Type": "application/json" }); + return res.end(JSON.stringify({ ok: true, data: newItem })); + } + + if (req.method === "GET" && urlPath === "/api/stats") { + const items = readItems(); + const today = new Date().toDateString(); + const todayCount = items.filter(p => new Date(p.registeredAt).toDateString() === today).length; + res.writeHead(200, { "Content-Type": "application/json" }); + return res.end(JSON.stringify({ total: items.length, today: todayCount })); + } + + let file = req.url === "/" ? "/index.html" : urlPath; + const full = path.join(__dirname, file); + if (full.startsWith(__dirname) && fs.existsSync(full) && fs.statSync(full).isFile()) { + const ext = path.extname(full); + const type = ext === ".css" ? "text/css" : ext === ".js" ? "application/javascript" : "text/html"; + res.writeHead(200, { "Content-Type": type + "; charset=utf-8" }); + return res.end(fs.readFileSync(full)); + } + + res.writeHead(404); res.end("Not found"); +}).listen(PORT, () => console.log("Сервер запущен на порту " + PORT));