diff --git a/index.html b/index.html
index 47ede14532..44d7f80cc0 100644
--- a/index.html
+++ b/index.html
@@ -8,46 +8,7 @@
-
Загрузка комментариев...
-
-
-
-
-
-
-
-
- Чтобы добавить комментарий, авторизуйтесь.
-
-
-
-
Авторизация
-
-
-
-
-
-
-
-
-
-
-
Регистрация
-
-
-
-
-
-
-
-
-
+
diff --git a/js/api.js b/js/api.js
index 308601ed9e..0323c4b6e2 100644
--- a/js/api.js
+++ b/js/api.js
@@ -1,23 +1,61 @@
+import { logout } from "./auth.js";
+
+
const PERSONAL_KEY = "polina-rebrova";
const API_URL = `https://wedev-api.sky.pro/api/v2/${PERSONAL_KEY}/comments`;
-const AUTH_URL = "https://wedev-api.sky.pro/api/v2//user";
+const USER_API_URL = "https://wedev-api.sky.pro/api/user";
+
+
+async function handleUnauthorized(response) {
+ if (response.status === 401) {
+ logout();
+ alert("Сессия истекла. Пожалуйста, войдите снова.");
+ window.location.reload();
+ throw new Error("Неавторизован");
+ }
+ return response;
+}
+
+async function checkResponse(response) {
+ const contentType = response.headers.get("content-type");
+
+
+ if (contentType && contentType.includes("text/html")) {
+ console.error("Сервер вернул HTML вместо JSON. URL:", response.url);
+ throw new Error(`Ошибка сервера: ${response.status} ${response.statusText}`);
+ }
+
+ return response;
+}
export async function fetchComments() {
try {
+ console.log("Запрос к API:", API_URL);
+
const response = await fetch(API_URL);
- if (!response.ok) throw new Error("Ошибка загрузки комментариев");
-
+ await checkResponse(response);
+ await handleUnauthorized(response);
+
+ if (!response.ok) throw new Error(`Ошибка загрузки комментариев: ${response.status}`);
+
const data = await response.json();
+
+ if (!data.comments || !Array.isArray(data.comments)) {
+ throw new Error("Неверный формат ответа от сервера");
+ }
+
return data.comments.map((comment) => ({
+ id: comment.id,
author: comment.author.name,
+ authorLogin: comment.author.login,
text: comment.text,
- date: new Date(comment.date).toLocaleString("ru-RU"),
+ date: comment.date,
likes: comment.likes,
- isLiked: comment.isLiked,
+ isLiked: comment.isLiked || false,
}));
} catch (error) {
- alert("Ошибка загрузки комментариев");
- return [];
+ console.error("Ошибка загрузки комментариев:", error);
+ throw error;
}
}
@@ -30,31 +68,88 @@ export async function postComment(text) {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
- "Content-Type": "application/json",
},
body: JSON.stringify({ text }),
});
+ await checkResponse(response);
+ await handleUnauthorized(response);
+
+ if (response.status === 400) {
+ const error = await response.json();
+ throw new Error(error.error || "Ошибка валидации");
+ }
+
if (!response.ok) throw new Error("Ошибка добавления комментария");
- return await fetchComments();
+
+ return await response.json();
+ } catch (error) {
+ console.error("Ошибка добавления комментария:", error);
+ throw error;
+ }
+}
+
+export async function toggleLike(commentId) {
+ const token = localStorage.getItem("token");
+ if (!token) throw new Error("Нет авторизации");
+
+ try {
+ const response = await fetch(`${API_URL}/${commentId}/toggle-like`, {
+ method: "POST",
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ });
+
+ await checkResponse(response);
+ await handleUnauthorized(response);
+
+ if (!response.ok) throw new Error("Ошибка переключения лайка");
+
+ const data = await response.json();
+ return data.result;
} catch (error) {
- alert("Ошибка добавления комментария");
- return [];
+ console.error("Ошибка лайка:", error);
+ throw error;
}
}
export async function login(login, password) {
- return fetch(AUTH_URL + "/login", {
+ const response = await fetch(`${USER_API_URL}/login`, {
method: "POST",
- headers: { "Content-Type": "application/json" },
body: JSON.stringify({ login, password }),
});
+
+ await checkResponse(response);
+
+ if (response.status === 400) {
+ const error = await response.json();
+ throw new Error(error.error || "Неправильный логин или пароль");
+ }
+
+ if (!response.ok) {
+ throw new Error("Ошибка авторизации");
+ }
+
+ return response.json();
}
export async function registration(name, login, password) {
- return fetch(AUTH_URL, {
+ const response = await fetch(USER_API_URL, {
method: "POST",
- headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name, login, password }),
});
+
+ await checkResponse(response);
+
+ if (response.status === 400) {
+ const error = await response.json();
+ throw new Error(error.error || "Пользователь с таким логином уже существует");
+ }
+
+ if (!response.ok) {
+ throw new Error("Ошибка регистрации");
+ }
+
+ return response.json();
}
\ No newline at end of file
diff --git a/js/auth.js b/js/auth.js
index ee0fca89ea..4ecfe522d6 100644
--- a/js/auth.js
+++ b/js/auth.js
@@ -1,21 +1,39 @@
let currentUser = null;
+export function setCurrentUser(user) {
+ currentUser = user;
+ if (user && user.token) {
+ localStorage.setItem("token", user.token);
+ localStorage.setItem("userName", user.name);
+ localStorage.setItem("userLogin", user.login);
+ } else {
+ localStorage.removeItem("token");
+ localStorage.removeItem("userName");
+ localStorage.removeItem("userLogin");
+ }
+}
+
export function getCurrentUser() {
- if (!currentUser) {
- const savedUser = localStorage.getItem("user");
- if (savedUser) {
- currentUser = JSON.parse(savedUser);
- }
+ if (currentUser) return currentUser;
+
+ const token = localStorage.getItem("token");
+ const name = localStorage.getItem("userName");
+ const login = localStorage.getItem("userLogin");
+
+ if (token && name) {
+ currentUser = { token, name, login };
+ return currentUser;
}
- return currentUser;
+ return null;
}
export function checkAuth() {
- return localStorage.getItem("token") !== null;
+ return !!getCurrentUser();
}
export function logout() {
- localStorage.removeItem("token");
- localStorage.removeItem("user");
currentUser = null;
+ localStorage.removeItem("token");
+ localStorage.removeItem("userName");
+ localStorage.removeItem("userLogin");
}
\ No newline at end of file
diff --git a/js/comments.js b/js/comments.js
index feaceee0f7..ab52764af1 100644
--- a/js/comments.js
+++ b/js/comments.js
@@ -1,4 +1,4 @@
-import { fetchComments, postComment } from "./api.js";
+import { fetchComments, postComment, toggleLike } from "./api.js";
import { renderComments } from "./render.js";
import { getCurrentUser } from "./auth.js";
@@ -6,16 +6,16 @@ export let comments = [];
export async function loadComments() {
const loadingMessage = document.getElementById("loading-message");
- loadingMessage.style.display = "block";
+ if (loadingMessage) loadingMessage.style.display = "block";
try {
comments = await fetchComments();
renderComments();
} catch (error) {
console.error("Ошибка при загрузке комментариев:", error);
- loadingMessage.textContent = "Ошибка загрузки комментариев";
+ if (loadingMessage) loadingMessage.textContent = "Ошибка загрузки комментариев";
} finally {
- loadingMessage.style.display = "none";
+ if (loadingMessage) loadingMessage.style.display = "none";
}
}
@@ -23,36 +23,53 @@ export async function addComment(text) {
const user = getCurrentUser();
if (!user) {
alert("Сначала авторизуйтесь!");
- return;
+ return false;
}
if (text.length < 3) {
alert("Комментарий должен быть не короче 3 символов");
- return;
+ return false;
}
const addForm = document.getElementById("add-form");
const commentLoadingMessage = document.getElementById("comment-loading-message");
const addButton = document.getElementById("add-comment-button");
+ const commentInput = document.getElementById("comment-input");
- addForm.style.display = "none";
- commentLoadingMessage.style.display = "block";
- addButton.disabled = true;
+ if (addForm) addForm.style.display = "none";
+ if (commentLoadingMessage) commentLoadingMessage.style.display = "block";
+ if (addButton) addButton.disabled = true;
try {
await postComment(text);
await loadComments();
+ if (commentInput) commentInput.value = "";
+ return true;
+ } catch (error) {
+ alert(error.message || "Ошибка добавления комментария");
+ return false;
} finally {
- addForm.style.display = "block";
- commentLoadingMessage.style.display = "none";
- addButton.disabled = false;
+ if (addForm) addForm.style.display = "block";
+ if (commentLoadingMessage) commentLoadingMessage.style.display = "none";
+ if (addButton) addButton.disabled = false;
}
}
-export function toggleLike(index) {
- if (!comments[index]) return;
+export async function handleToggleLike(commentId, index) {
+ const user = getCurrentUser();
+ if (!user) {
+ alert("Авторизуйтесь, чтобы ставить лайки!");
+ return;
+ }
- comments[index].isLiked = !comments[index].isLiked;
- comments[index].likes += comments[index].isLiked ? 1 : -1;
- renderComments();
-}
+ try {
+ const result = await toggleLike(commentId);
+ if (result) {
+ comments[index].likes = result.likes;
+ comments[index].isLiked = result.isLiked;
+ renderComments();
+ }
+ } catch (error) {
+ alert("Ошибка при установке лайка");
+ }
+}
\ No newline at end of file
diff --git a/js/eventHandlers.js b/js/eventHandlers.js
index 20a0829f2a..863aca5bc0 100644
--- a/js/eventHandlers.js
+++ b/js/eventHandlers.js
@@ -1,45 +1,43 @@
import { addComment, toggleLike } from "./comments.js";
import { renderComments } from "./render.js";
-export function addEventListeners() {
+export function initEventHandlers() {
+ initAddCommentHandler();
+}
+
+
+export function initAddCommentHandler() {
const addButton = document.getElementById("add-comment-button");
const commentInput = document.getElementById("comment-input");
if (!addButton || !commentInput) {
- console.error("Ошибка: один из элементов формы не найден!");
+ console.error("Ошибка: элементы формы не найдены!");
return;
}
- addButton.addEventListener("click", () => {
- if (commentInput.value.trim()) {
- addComment(commentInput.value.trim());
+
+ const newAddButton = addButton.cloneNode(true);
+ addButton.parentNode.replaceChild(newAddButton, addButton);
+
+ newAddButton.addEventListener("click", async () => {
+ const text = commentInput.value.trim();
+ if (text) {
+ await addComment(text);
commentInput.value = "";
- renderComments();
+
+ } else {
+ alert("Введите текст комментария");
}
});
}
-export function addLikeEventListeners() {
- document.querySelectorAll(".like-button").forEach((button) => {
- button.addEventListener("click", (event) => {
- event.stopPropagation();
- const commentIndex = event.target.dataset.index;
- toggleLike(commentIndex);
- renderComments();
- });
- });
+
+export function initLikeHandlers() {
+
+ console.log("Like handlers are now in render.js");
}
-export function addReplyListeners() {
- document.querySelectorAll(".comment").forEach((comment) => {
- comment.addEventListener("click", (event) => {
- if (event.target.classList.contains("like-button")) return;
- const index = event.currentTarget.dataset.index;
- const textInput = document.getElementById("comment-input");
-
- if (comments[index]) {
- textInput.value = `> ${comments[index].text}\n`;
- }
- });
- });
+export function initReplyHandlers() {
+
+ console.log("Reply handlers are now in render.js");
}
\ No newline at end of file
diff --git a/js/main.js b/js/main.js
index 97079e2432..dcaabb3064 100644
--- a/js/main.js
+++ b/js/main.js
@@ -1,64 +1,111 @@
+import { loadComments } from "./comments.js";
import { renderComments } from "./render.js";
-import { loadComments, comments } from "./comments.js";
-import { checkAuth } from "./auth.js";
-import { showLoginForm, showRegisterForm } from "./render.js";
+import { checkAuth, getCurrentUser } from "./auth.js";
+import { renderLoginForm } from "./renderLogin.js";
+import { renderAddForm } from "./renderAddForm.js";
-document.addEventListener("DOMContentLoaded", async () => {
- const authMessage = document.getElementById("auth-message");
- const authLink = document.getElementById("auth-link");
- const commentsContainer = document.getElementById("comments-container");
- const addForm = document.getElementById("add-form");
- const loginContainer = document.getElementById("login-container");
- const registerContainer = document.getElementById("register-container");
+let container = null;
+let loadingMessage = null;
- await loadComments();
- renderComments();
-
- if (checkAuth()) {
- showCommentsUI();
- } else {
- showAuthMessage();
+function initContainer() {
+ container = document.querySelector(".container");
+ if (!container) {
+ console.error("Container not found");
+ return false;
}
+ return true;
+}
- function showCommentsUI() {
- if (!authMessage || !commentsContainer || !addForm || !loginContainer || !registerContainer) {
- console.error("Ошибка: один из элементов не найден!");
- return;
- }
- authMessage.style.display = "none";
- loginContainer.style.display = "none";
- registerContainer.style.display = "none";
- commentsContainer.style.display = "block";
- addForm.style.display = "block";
- }
+function showLoading() {
+ loadingMessage = document.createElement("p");
+ loadingMessage.id = "loading-message";
+ loadingMessage.textContent = "Загрузка комментариев...";
+ container.appendChild(loadingMessage);
+}
- function showAuthMessage() {
- if (!authMessage || !commentsContainer || !addForm || !loginContainer || !registerContainer) {
- console.error("Ошибка: один из элементов не найден!");
- return;
- }
- authMessage.style.display = "block";
- commentsContainer.style.display = "block";
- addForm.style.display = "none";
- loginContainer.style.display = "none";
- registerContainer.style.display = "none";
+function hideLoading() {
+ if (loadingMessage && loadingMessage.parentNode) {
+ loadingMessage.remove();
}
+}
- if (authLink) {
- authLink.addEventListener("click", (event) => {
- event.preventDefault();
- showLoginForm();
- });
- } else {
- console.error("Ошибка: auth-link не найден!");
+function clearContainer() {
+ while (container.firstChild) {
+ container.removeChild(container.firstChild);
}
-});
+}
+
+export function showCommentsUI() {
+ if (!container) return;
+
+ clearContainer();
+
+ const commentsList = document.createElement("ul");
+ commentsList.id = "comments-list";
+ commentsList.className = "comments";
+ container.appendChild(commentsList);
+
+
+ renderComments();
+
+
+ renderAddForm();
+}
+
+function showAuthMessage() {
+ if (!container) return;
+
+ clearContainer();
+
+
+ const commentsList = document.createElement("ul");
+ commentsList.id = "comments-list";
+ commentsList.className = "comments";
+ container.appendChild(commentsList);
+
+
+ renderComments();
+
+
+ const authMessage = document.createElement("p");
+ authMessage.id = "auth-message";
+ authMessage.style.display = "block";
+ authMessage.style.marginTop = "20px";
+ authMessage.style.textAlign = "center";
+
+ const authLink = document.createElement("a");
+ authLink.href = "#";
+ authLink.id = "auth-link";
+ authLink.className = "link-login";
+ authLink.textContent = "авторизуйтесь";
+
+ authMessage.appendChild(document.createTextNode("Чтобы добавить комментарий, "));
+ authMessage.appendChild(authLink);
+
+ container.appendChild(authMessage);
+
+
authLink.addEventListener("click", (event) => {
event.preventDefault();
- showLoginForm();
+ renderLoginForm();
});
+}
- registerLink.addEventListener("click", (event) => {
- event.preventDefault();
- showRegisterForm();
- });
+export async function init() {
+ if (!initContainer()) return;
+
+ showLoading();
+
+ await loadComments();
+
+ hideLoading();
+
+ if (checkAuth()) {
+ showCommentsUI();
+ } else {
+ showAuthMessage();
+ }
+}
+
+
+document.addEventListener("DOMContentLoaded", init);
\ No newline at end of file
diff --git a/js/render.js b/js/render.js
index 2eee4efb5c..7565ba466e 100644
--- a/js/render.js
+++ b/js/render.js
@@ -1,83 +1,104 @@
-import { comments } from "./comments.js";
-import { addLikeEventListeners, addReplyListeners } from "./eventHandlers.js";
-import { getCurrentUser } from "./auth.js";
-
-export function renderComments() {
- const commentsList = document.getElementById("comments-list");
-
- if (!commentsList) {
- console.error("Ошибка: элемент #comments-list не найден!");
- return;
- }
-
- commentsList.innerHTML = comments
- .map((comment, index) => `
-
- `)
- .join("");
-
- addLikeEventListeners();
- addReplyListeners();
- renderCommentForm();
-}
-
-export function renderCommentForm() {
- const container = document.querySelector(".container");
- const user = getCurrentUser();
- const formContainer = document.getElementById("comment-form-container");
-
- if (formContainer) {
- formContainer.remove();
- }
-
- const formHtml = user
- ? `
-
-
- `
- : ``;
-
- container.insertAdjacentHTML("beforeend", formHtml);
-
- if (!user) {
- document.getElementById("login-link").addEventListener("click", (event) => {
- event.preventDefault();
- showLoginForm();
- });
- }
-}
-
-
-export function showLoginForm() {
- document.getElementById("auth-message").style.display = "none";
- document.getElementById("comments-container").style.display = "none";
- document.getElementById("login-container").style.display = "block";
- document.getElementById("register-container").style.display = "none";
-}
-
-export function showRegisterForm() {
- document.getElementById("auth-message").style.display = "none";
- document.getElementById("comments-container").style.display = "none";
- document.getElementById("login-container").style.display = "none";
- document.getElementById("register-container").style.display = "block";
+import { comments, handleToggleLike } from "./comments.js";
+import { sanitize, formatDate } from "./utils.js";
+
+export function renderComments() {
+ const commentsList = document.getElementById("comments-list");
+ if (!commentsList) {
+ console.error("comments-list не найден");
+ return;
+ }
+
+
+ while (commentsList.firstChild) {
+ commentsList.removeChild(commentsList.firstChild);
+ }
+
+ if (comments.length === 0) {
+ const emptyMessage = document.createElement("li");
+ emptyMessage.className = "comment";
+ emptyMessage.textContent = "Комментариев пока нет";
+ commentsList.appendChild(emptyMessage);
+ return;
+ }
+
+
+ comments.forEach((comment, index) => {
+ const commentItem = createCommentElement(comment, index);
+ commentsList.appendChild(commentItem);
+ });
+}
+
+export function createCommentElement(comment, index) {
+ const li = document.createElement("li");
+ li.className = "comment";
+ li.dataset.index = index;
+
+
+ const header = document.createElement("div");
+ header.className = "comment-header";
+
+ const author = document.createElement("div");
+ author.className = "comment-author";
+ author.textContent = sanitize(comment.author);
+
+ const date = document.createElement("div");
+ date.className = "comment-date";
+ date.textContent = formatDate(comment.date);
+
+ header.appendChild(author);
+ header.appendChild(date);
+
+
+ const body = document.createElement("div");
+ body.className = "comment-body";
+
+ const text = document.createElement("div");
+ text.className = "comment-text";
+ text.textContent = sanitize(comment.text);
+
+ body.appendChild(text);
+
+
+ const footer = document.createElement("div");
+ footer.className = "comment-footer";
+
+ const likesContainer = document.createElement("div");
+ likesContainer.className = "likes";
+
+ const likesCounter = document.createElement("span");
+ likesCounter.className = "likes-counter";
+ likesCounter.textContent = comment.likes;
+
+ const likeButton = document.createElement("button");
+ likeButton.className = `like-button ${comment.isLiked ? "liked" : ""}`;
+ likeButton.dataset.id = comment.id;
+ likeButton.dataset.index = index;
+
+
+ likeButton.addEventListener("click", async (event) => {
+ event.stopPropagation();
+ await handleToggleLike(comment.id, index);
+ });
+
+ likesContainer.appendChild(likesCounter);
+ likesContainer.appendChild(likeButton);
+ footer.appendChild(likesContainer);
+
+
+ li.addEventListener("click", (event) => {
+
+ if (event.target.classList.contains("like-button")) return;
+
+ const commentInput = document.getElementById("comment-input");
+ if (commentInput) {
+ commentInput.value = `> ${comment.text}\n\n`;
+ commentInput.focus();
+ }
+ });
+
+ li.appendChild(header);
+ li.appendChild(body);
+ li.appendChild(footer);
+
+ return li;
}
\ No newline at end of file
diff --git a/js/renderAddForm.js b/js/renderAddForm.js
new file mode 100644
index 0000000000..b511b79e9d
--- /dev/null
+++ b/js/renderAddForm.js
@@ -0,0 +1,65 @@
+import { addComment } from "./comments.js";
+import { getCurrentUser } from "./auth.js";
+
+export function renderAddForm() {
+ const container = document.querySelector(".container");
+ if (!container) return;
+
+ const user = getCurrentUser();
+ if (!user) return;
+
+
+ if (document.getElementById("add-form")) return;
+
+ const addForm = document.createElement("div");
+ addForm.id = "add-form";
+ addForm.className = "add-form";
+
+
+ const nameInput = document.createElement("input");
+ nameInput.type = "text";
+ nameInput.id = "name-input";
+ nameInput.className = "add-form-name";
+ nameInput.value = user.name;
+ nameInput.readOnly = true;
+ addForm.appendChild(nameInput);
+
+
+ const textarea = document.createElement("textarea");
+ textarea.id = "comment-input";
+ textarea.className = "add-form-text";
+ textarea.placeholder = "Введите ваш комментарий";
+ textarea.rows = 4;
+ addForm.appendChild(textarea);
+
+
+ const buttonRow = document.createElement("div");
+ buttonRow.className = "add-form-row";
+
+ const addButton = document.createElement("button");
+ addButton.id = "add-comment-button";
+ addButton.className = "add-form-button";
+ addButton.textContent = "Написать";
+
+ addButton.addEventListener("click", async () => {
+ const text = textarea.value.trim();
+ if (text) {
+ await addComment(text);
+ textarea.value = "";
+ } else {
+ alert("Введите текст комментария");
+ }
+ });
+
+ buttonRow.appendChild(addButton);
+ addForm.appendChild(buttonRow);
+
+
+ const loadingMessage = document.createElement("p");
+ loadingMessage.id = "comment-loading-message";
+ loadingMessage.style.display = "none";
+ loadingMessage.textContent = "Комментарий добавляется...";
+
+ container.appendChild(addForm);
+ container.appendChild(loadingMessage);
+}
\ No newline at end of file
diff --git a/js/renderLogin.js b/js/renderLogin.js
new file mode 100644
index 0000000000..f9bf78bdc2
--- /dev/null
+++ b/js/renderLogin.js
@@ -0,0 +1,108 @@
+import { login } from "./api.js";
+import { setCurrentUser } from "./auth.js";
+import { showRegisterForm } from "./renderRegister.js";
+import { init } from "./main.js";
+
+let container = null;
+
+function clearContainer() {
+ const container = document.querySelector(".container");
+ if (!container) return;
+ while (container.firstChild) {
+ container.removeChild(container.firstChild);
+ }
+}
+
+export function renderLoginForm() {
+ container = document.querySelector(".container");
+ if (!container) return;
+
+ clearContainer();
+
+
+ const loginContainer = document.createElement("div");
+ loginContainer.id = "login-container";
+ loginContainer.className = "auth-container";
+
+
+ const title = document.createElement("h2");
+ title.className = "auth-title";
+ title.textContent = "Авторизация";
+ loginContainer.appendChild(title);
+
+
+ const loginInput = document.createElement("input");
+ loginInput.type = "text";
+ loginInput.id = "login-input";
+ loginInput.className = "auth-input";
+ loginInput.placeholder = "Введите логин";
+ loginContainer.appendChild(loginInput);
+
+
+ const passwordInput = document.createElement("input");
+ passwordInput.type = "password";
+ passwordInput.id = "password-input";
+ passwordInput.className = "auth-input";
+ passwordInput.placeholder = "Введите пароль";
+ loginContainer.appendChild(passwordInput);
+
+
+ const buttonsDiv = document.createElement("div");
+ buttonsDiv.className = "auth-buttons";
+
+ const loginButton = document.createElement("button");
+ loginButton.id = "login-button";
+ loginButton.className = "auth-button";
+ loginButton.textContent = "Войти";
+
+ const registerLink = document.createElement("button");
+ registerLink.id = "register-link";
+ registerLink.className = "auth-button";
+ registerLink.textContent = "Регистрация";
+
+ buttonsDiv.appendChild(loginButton);
+ buttonsDiv.appendChild(registerLink);
+ loginContainer.appendChild(buttonsDiv);
+
+
+ const errorElement = document.createElement("p");
+ errorElement.id = "login-error";
+ errorElement.className = "error-message";
+ loginContainer.appendChild(errorElement);
+
+ container.appendChild(loginContainer);
+
+ const handleLogin = async () => {
+ const loginValue = loginInput.value.trim();
+ const passwordValue = passwordInput.value;
+
+ if (!loginValue || !passwordValue) {
+ errorElement.textContent = "Заполните все поля";
+ return;
+ }
+
+ try {
+ const userData = await login(loginValue, passwordValue);
+ if (userData && userData.user) {
+ setCurrentUser(userData.user);
+ await init();
+ }
+ } catch (error) {
+ errorElement.textContent = error.message;
+ }
+ };
+
+ loginButton.addEventListener("click", handleLogin);
+ registerLink.addEventListener("click", (e) => {
+ e.preventDefault();
+ showRegisterForm();
+ });
+
+ loginInput.addEventListener("keypress", (e) => {
+ if (e.key === "Enter") handleLogin();
+ });
+
+ passwordInput.addEventListener("keypress", (e) => {
+ if (e.key === "Enter") handleLogin();
+ });
+}
\ No newline at end of file
diff --git a/js/renderRegister.js b/js/renderRegister.js
new file mode 100644
index 0000000000..f65cf3bb33
--- /dev/null
+++ b/js/renderRegister.js
@@ -0,0 +1,115 @@
+import { registration } from "./api.js";
+import { setCurrentUser } from "./auth.js";
+import { renderLoginForm } from "./renderLogin.js";
+import { init } from "./main.js";
+
+function clearContainer() {
+ const container = document.querySelector(".container");
+ if (!container) return;
+ while (container.firstChild) {
+ container.removeChild(container.firstChild);
+ }
+}
+
+export function showRegisterForm() {
+ const container = document.querySelector(".container");
+ if (!container) return;
+
+ clearContainer();
+
+
+ const registerContainer = document.createElement("div");
+ registerContainer.id = "register-container";
+ registerContainer.className = "auth-container";
+
+ const title = document.createElement("h2");
+ title.className = "auth-title";
+ title.textContent = "Регистрация";
+ registerContainer.appendChild(title);
+
+
+ const nameInput = document.createElement("input");
+ nameInput.type = "text";
+ nameInput.id = "register-name";
+ nameInput.className = "auth-input";
+ nameInput.placeholder = "Введите имя";
+ registerContainer.appendChild(nameInput);
+
+
+ const loginInput = document.createElement("input");
+ loginInput.type = "text";
+ loginInput.id = "register-login";
+ loginInput.className = "auth-input";
+ loginInput.placeholder = "Введите логин";
+ registerContainer.appendChild(loginInput);
+
+
+ const passwordInput = document.createElement("input");
+ passwordInput.type = "password";
+ passwordInput.id = "register-password";
+ passwordInput.className = "auth-input";
+ passwordInput.placeholder = "Введите пароль";
+ registerContainer.appendChild(passwordInput);
+
+
+ const buttonsDiv = document.createElement("div");
+ buttonsDiv.className = "auth-buttons";
+
+ const registerButton = document.createElement("button");
+ registerButton.id = "register-button";
+ registerButton.className = "auth-button";
+ registerButton.textContent = "Зарегистрироваться";
+
+ const backButton = document.createElement("button");
+ backButton.id = "back-to-login";
+ backButton.className = "auth-button";
+ backButton.textContent = "Назад";
+
+ buttonsDiv.appendChild(registerButton);
+ buttonsDiv.appendChild(backButton);
+ registerContainer.appendChild(buttonsDiv);
+
+ const errorElement = document.createElement("p");
+ errorElement.id = "register-error";
+ errorElement.className = "error-message";
+ registerContainer.appendChild(errorElement);
+
+ container.appendChild(registerContainer);
+
+ const handleRegister = async () => {
+ const name = nameInput.value.trim();
+ const login = loginInput.value.trim();
+ const password = passwordInput.value;
+
+ if (!name || !login || !password) {
+ errorElement.textContent = "Заполните все поля";
+ return;
+ }
+
+ if (name.length < 2) {
+ errorElement.textContent = "Имя должно быть не короче 2 символов";
+ return;
+ }
+
+ if (password.length < 6) {
+ errorElement.textContent = "Пароль должен быть не короче 6 символов";
+ return;
+ }
+
+ try {
+ const userData = await registration(name, login, password);
+ if (userData && userData.user) {
+ setCurrentUser(userData.user);
+ await init();
+ }
+ } catch (error) {
+ errorElement.textContent = error.message;
+ }
+ };
+
+ registerButton.addEventListener("click", handleRegister);
+ backButton.addEventListener("click", (e) => {
+ e.preventDefault();
+ renderLoginForm();
+ });
+}
\ No newline at end of file
diff --git a/js/sanitize.js b/js/sanitize.js
deleted file mode 100644
index 299677099e..0000000000
--- a/js/sanitize.js
+++ /dev/null
@@ -1,9 +0,0 @@
-export function sanitize(text) {
- return text
- .replaceAll("&", "&")
- .replaceAll("<", "<")
- .replaceAll(">", ">")
- .replaceAll('"', """)
- .replaceAll("'", "'");
- }
-
\ No newline at end of file
diff --git a/js/utils.js b/js/utils.js
index 6fea44db0b..a94cf1eb27 100644
--- a/js/utils.js
+++ b/js/utils.js
@@ -1,4 +1,20 @@
-export function formatDate(date) {
- return new Date(date).toLocaleString("ru-RU");
- }
-
\ No newline at end of file
+export function sanitize(text) {
+ if (!text) return "";
+ return text
+ .replaceAll("&", "&")
+ .replaceAll("<", "<")
+ .replaceAll(">", ">")
+ .replaceAll('"', """)
+ .replaceAll("'", "'");
+}
+
+export function formatDate(dateString) {
+ const date = new Date(dateString);
+ return date.toLocaleString("ru-RU", {
+ day: "numeric",
+ month: "numeric",
+ year: "numeric",
+ hour: "2-digit",
+ minute: "2-digit",
+ });
+}
\ No newline at end of file
diff --git a/styles.css b/styles.css
index e35e866d25..3e3afc0d1b 100644
--- a/styles.css
+++ b/styles.css
@@ -209,3 +209,63 @@ body {
border-radius: 18px;
cursor: pointer;
}
+
+
+.auth-container {
+ width: 596px;
+ background: radial-gradient(
+ 75.42% 75.42% at 50% 42.37%,
+ rgba(53, 53, 53, 0) 22.92%,
+ #7334ea 100%
+ );
+ border-radius: 20px;
+ padding: 48px;
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+}
+
+.auth-title {
+ margin: 0 0 16px 0;
+ text-align: center;
+}
+
+.auth-input {
+ font-size: 16px;
+ font-family: Helvetica;
+ border-radius: 8px;
+ border: none;
+ padding: 11px 22px;
+}
+
+.auth-buttons {
+ display: flex;
+ gap: 16px;
+ justify-content: center;
+ margin-top: 16px;
+}
+
+.auth-button {
+ font-size: 18px;
+ padding: 10px 20px;
+ background-color: #bcec30;
+ border: none;
+ border-radius: 18px;
+ cursor: pointer;
+}
+
+.auth-button:hover {
+ opacity: 0.9;
+}
+
+.error-message {
+ color: #ff6b6b;
+ text-align: center;
+ margin: 8px 0 0 0;
+}
+
+#loading-message,
+#comment-loading-message {
+ text-align: center;
+ color: #bcec30;
+}
\ No newline at end of file