diff --git a/api.js b/api.js index 123a9e3b6..a099af2ee 100644 --- a/api.js +++ b/api.js @@ -1,8 +1,11 @@ +import { getToken, user, posts } from "./index.js"; +import { renderPostsPageComponent } from "./components/posts-page-component.js"; + // Замени на свой, чтобы получить независимый от других набор данных. // "боевая" версия инстапро лежит в ключе prod -const personalKey = "prod"; +const personalKey = "tatiana-alekseeva"; const baseHost = "https://webdev-hw-api.vercel.app"; -const postsHost = `${baseHost}/api/v1/${personalKey}/instapro`; +const postsHost = `https://wedev-api.sky.pro/api/v1/:${personalKey}/instapro`; export function getPosts({ token }) { return fetch(postsHost, { @@ -19,10 +22,123 @@ export function getPosts({ token }) { return response.json(); }) .then((data) => { - return data.posts; + const appPosts = data.posts.map((post) => { + return { + id: post.id, + imageUrl: post.imageUrl, + createdAt: post.createdAt, + description: post.description, + userId: post.user.id, + userName: post.user.name, + userLogin: post.user.login, + userImg: post.user.imageUrl, + likes: post.likes || [], + isLiked: post.isLiked, + }; + }); + + return appPosts; + }); +} + +export function fetchUserPosts(userId) { + return fetch(postsHost + `/user-posts/${userId}`) + .then((response) => { + return response.json(); + }) + .then((data) => { + const appPosts = data.posts.map((post) => { + return { + id: post.id, + imageUrl: post.imageUrl, + createdAt: post.createdAt, + description: post.description, + userId: post.user.id, + userName: post.user.name, + userLogin: post.user.login, + userImg: post.user.imageUrl, + likes: post.likes || [], + isLiked: post.isLiked, + }; + }); + + return appPosts; + }); +} + +export function fetchLikePosts(postId, isLiked) { + if (!user || !user._id || !user.name) { + throw new Error("Пользователь не авторизован"); + } + + const userId = user._id; + const userName = user.name; + const method = isLiked ? "dislike" : "like"; + console.log(user._id); + console.log(user.name); + + return fetch(`${postsHost}/${postId}/${method}`, { + method: "POST", + headers: { + Authorization: getToken(), + }, + body: JSON.stringify({ + postId, + isLiked, + userId, + userName, + }), + }) + .then((response) => { + if (!response.ok) { + throw new Error("Ошибка при обработке лайка"); + } + + console.log(response); + return response.json(); + }) + .then((data) => { + const index = posts.findIndex((p) => p.id === postId); + if (index !== -1) { + posts[index] = { + ...posts[index], + isLiked: !posts[index].isLiked, + likes: data.post.likes, + }; + } + console.log(data); + }) + .catch((error) => { + console.error("Ошибка:", error); }); } +export function onAddPostClick(description, imageUrl) { + return fetch(postsHost, { + method: "POST", + headers: { + Authorization: getToken(), + }, + body: JSON.stringify({ + description, + imageUrl, + }), + }).then((response) => { + if (response.status === 500) { + throw new Error("Ошибка сервера"); + } + if (response.status === 401) { + throw new Error("Нет авторизации"); + } + if (response.status === 400) { + throw new Error("Неверный запрос"); + } + if (response.status === 201) { + return response.json(); + } + }); +} + export function registerUser({ login, password, name, imageUrl }) { return fetch(baseHost + "/api/user", { method: "POST", diff --git a/components/add-post-page-component.js b/components/add-post-page-component.js index 8277f093b..e95243517 100644 --- a/components/add-post-page-component.js +++ b/components/add-post-page-component.js @@ -1,23 +1,66 @@ +import { onAddPostClick } from "../api.js"; +import { renderUploadImageComponent } from "./upload-image-component.js"; + export function renderAddPostPageComponent({ appEl, onAddPostClick }) { const render = () => { // @TODO: Реализовать страницу добавления поста const appHtml = `
-
- Cтраница добавления поста - +
+
- `; +
+

Добавить пост

+
+
+
+ +
+
+ + +
+
+
`; appEl.innerHTML = appHtml; - document.getElementById("add-button").addEventListener("click", () => { - onAddPostClick({ - description: "Описание картинки", - imageUrl: "https://image.png", + let imageUrl = ""; + const descriptionEl = document.getElementById("description"); + const uploadImageContainer = document.querySelector( + ".upload-image-container", + ); + const buttonAdd = document.getElementById("add-button"); + if (uploadImageContainer) { + renderUploadImageComponent({ + element: uploadImageContainer, + onImageUrlChange(newImageUrl) { + imageUrl = newImageUrl; + }, }); + } + buttonAdd.addEventListener("click", () => { + if (!descriptionEl.value.trim() || imageUrl == "") { + alert("Заполните форму!"); + return; + } + onAddPostClick( + descriptionEl.value.replaceAll("<", "<").replaceAll(">", ">"), + imageUrl, + ); }); }; - render(); } diff --git a/components/auth-page-component.js b/components/auth-page-component.js index 0e93530ec..8a77b2b4f 100644 --- a/components/auth-page-component.js +++ b/components/auth-page-component.js @@ -125,9 +125,18 @@ export function renderAuthPageComponent({ appEl, setUser }) { }); } else { // Обработка регистрации - const login = document.getElementById("login-input").value; - const name = document.getElementById("name-input").value; - const password = document.getElementById("password-input").value; + const login = document + .getElementById("login-input") + .value.replaceAll("<", "<") + .replaceAll(">", ">"); + const name = document + .getElementById("name-input") + .value.replaceAll("<", "<") + .replaceAll(">", ">"); + const password = document + .getElementById("password-input") + .value.replaceAll("<", "<") + .replaceAll(">", ">"); if (!name) { alert("Введите имя"); diff --git a/components/formatDate.js b/components/formatDate.js new file mode 100644 index 000000000..2d875f06b --- /dev/null +++ b/components/formatDate.js @@ -0,0 +1,10 @@ +import { formatDistanceToNow } from "../node_modules/date-fns/formatDistanceToNow.js"; +import { ru } from "../node_modules/date-fns/locale/ru.js"; + +export function formatDate(date) { + return formatDistanceToNow(new Date(date), { + locale: ru, + includeSeconds: true, + addSuffix: true, + }); +} diff --git a/components/likes-component.js b/components/likes-component.js new file mode 100644 index 000000000..0c1690d30 --- /dev/null +++ b/components/likes-component.js @@ -0,0 +1,27 @@ +import { posts } from "../index.js"; +import { renderPostsPageComponent } from "./posts-page-component.js"; + +export const putLike = (postId) => { + const likeButtons = document.querySelectorAll(".like-button"); + + for (const likeButton of likeButtons) { + likeButton.addEventListener("click", (event) => { + event.stopPropagation(); + const postId = likeButton.dataset.postId; + const post = posts[index]; + + if (!post.isLiked) { + post.likes++; + post.isLiked = true; + } else { + post.likes--; + post.isLiked = false; + } + + renderPostsPageComponent(); + /*}) + .catch((error) => { + console.error("Ошибка при постановке лайка:", error);*/ + }); + } +}; diff --git a/components/posts-page-component.js b/components/posts-page-component.js index 662ccdbdc..9f3345120 100644 --- a/components/posts-page-component.js +++ b/components/posts-page-component.js @@ -1,95 +1,56 @@ import { USER_POSTS_PAGE } from "../routes.js"; import { renderHeaderComponent } from "./header-component.js"; -import { posts, goToPage } from "../index.js"; +import { posts, user } from "../index.js"; +import { renderUserPostsPageComponent } from "./user-posts-page-component.js"; +import { fetchLikePosts } from "../api.js"; +import { formatDate } from "./formatDate.js"; -export function renderPostsPageComponent({ appEl }) { +export function renderPostsPageComponent() { // @TODO: реализовать рендер постов из api - console.log("Актуальный список постов:", posts); + const appEl = document.getElementById("app"); - /** - * @TODO: чтобы отформатировать дату создания поста в виде "19 минут назад" - * можно использовать https://date-fns.org/v2.29.3/docs/formatDistanceToNow - */ - const appHtml = ` -
-
-