diff --git a/README.md b/README.md
index 216dfc2a..fe3f3edd 100644
--- a/README.md
+++ b/README.md
@@ -4,12 +4,12 @@ MVP аналога популярной соц. сети для обмена ф
## Ссылка на приложение:
-https::
+https://sciworker.github.io/webdev-cw-instapro-main1/
## Первоначальная оценка
-ХХХХ часов
+8 часов
## Фактически затраченное время
-YYYY часов
+10 часов
diff --git a/api.js b/api.js
index 8997c44d..c0238138 100644
--- a/api.js
+++ b/api.js
@@ -1,6 +1,6 @@
// Замени на свой, чтобы получить независимый от других набор данных.
// "боевая" версия инстапро лежит в ключе prod
-const personalKey = "prod";
+const personalKey = "Petr";
const baseHost = "https://webdev-hw-api.vercel.app";
const postsHost = `${baseHost}/api/v1/${personalKey}/instapro`;
@@ -15,7 +15,6 @@ export function getPosts({ token }) {
if (response.status === 401) {
throw new Error("Нет авторизации");
}
-
return response.json();
})
.then((data) => {
@@ -68,3 +67,71 @@ export function uploadImage({ file }) {
return response.json();
});
}
+
+// Создает новый пост
+export function createPost({ token, description, imageUrl }) {
+ return fetch(postsHost, {
+ method: "POST",
+ headers: {
+ Authorization: token
+
+ },
+ body: JSON.stringify({
+ description,
+ imageUrl,
+ }),
+ }).then((response) => {
+ if (response.status === 400) {
+ throw new Error("Ошибка создания поста");
+ }
+ return response.json();
+ });
+}
+
+export function getUserPosts({ userId, token }) {
+ return fetch(`${postsHost}/user-posts/${userId}`, {
+ method: "GET",
+ headers: {
+ Authorization: token,
+ },
+ })
+ .then(response => {
+ if (response.status === 401) {
+ throw new Error("Нет авторизации");
+ }
+ return response.json();
+ })
+ .then(data => {
+ return data.posts;
+ });
+}
+
+export function likePost({ postId, token }) {
+ return fetch(`${postsHost}/${postId}/like`, {
+ method: "POST",
+ headers: {
+ Authorization: token,
+ },
+ })
+ .then((response) => {
+ if (response.status === 401) {
+ throw new Error("Нет авторизации");
+ }
+ return response.json();
+ });
+}
+
+export function unlikePost({ postId, token }) {
+ return fetch(`${postsHost}/${postId}/dislike`, {
+ method: "POST",
+ headers: {
+ Authorization: token,
+ },
+ })
+ .then((response) => {
+ if (response.status === 401) {
+ throw new Error("Нет авторизации");
+ }
+ return response.json();
+ });
+}
diff --git a/components/add-post-page-component.js b/components/add-post-page-component.js
index 59554d86..d8b88ffb 100644
--- a/components/add-post-page-component.js
+++ b/components/add-post-page-component.js
@@ -1,23 +1,50 @@
+import { renderHeaderComponent } from "./header-component.js";
+import { renderUploadImageComponent } from "./upload-image-component.js";
+
export function renderAddPostPageComponent({ appEl, onAddPostClick }) {
+ let uploadedImageUrl = ""; // Переменная для хранения URL загруженного изображения
+
+ // Определите функцию для обработки изменения URL изображения
+ function handleImageUrlChange(newImageUrl) {
+ uploadedImageUrl = newImageUrl; // Сохраните новый URL изображения
+ }
+
const render = () => {
- // TODO: Реализовать страницу добавления поста
+ // Реализовать страницу добавления поста
const appHtml = `
-
- Cтраница добавления поста
-
-
- `;
+
+ `;
appEl.innerHTML = appHtml;
+ renderHeaderComponent({
+ element: document.querySelector(".header-container"),
+ });
+
+ renderUploadImageComponent({
+ element: document.querySelector(".upload-image-container"),
+ onImageUrlChange: handleImageUrlChange,
+ });
+
document.getElementById("add-button").addEventListener("click", () => {
+ const description = document.getElementById("description").value; // Получить описание из textarea
onAddPostClick({
- description: "Описание картинки",
- imageUrl: "https://image.png",
+ description: description,
+ imageUrl: uploadedImageUrl,
});
});
};
render();
-}
+}
\ No newline at end of file
diff --git a/components/header-component.js b/components/header-component.js
index 465fbb8f..cd999d06 100644
--- a/components/header-component.js
+++ b/components/header-component.js
@@ -39,3 +39,23 @@ export function renderHeaderComponent({ element }) {
return element;
}
+
+// export const renderHeaderComponent = ({ appEl, user, goToPage }) => {
+// const headerContainer = document.createElement('div');
+// headerContainer.className = 'header-container';
+
+// headerContainer.innerHTML = `
+//
+// Welcome ${user ? user.name : 'Guest'}
+// ${user ? '' : ''}
+//
+// `;
+
+// appEl.prepend(headerContainer);
+
+// if (user) {
+// document.getElementById('logout-btn').addEventListener('click', () => {
+// goToPage('logout');
+// });
+// }
+// };
diff --git a/components/posts-page-component.js b/components/posts-page-component.js
index 5b97fdfe..a668b603 100644
--- a/components/posts-page-component.js
+++ b/components/posts-page-component.js
@@ -1,97 +1,43 @@
import { USER_POSTS_PAGE } from "../routes.js";
import { renderHeaderComponent } from "./header-component.js";
-import { posts, goToPage } from "../index.js";
+import { posts, goToPage, user } from "../index.js";
+import { likePost, unlikePost } from "../api.js";
export function renderPostsPageComponent({ appEl }) {
- // TODO: реализовать рендер постов из api
console.log("Актуальный список постов:", posts);
- /**
- * TODO: чтобы отформатировать дату создания поста в виде "19 минут назад"
- * можно использовать https://date-fns.org/v2.29.3/docs/formatDistanceToNow
- */
const appHtml = `
-
-
-
- -
-
-
-

-
-
-
-
- Нравится: 2
-
-
-
- Иван Иваныч
- Ромашка, ромашка...
-
-
- 19 минут назад
-
-
- -
-
-
-
-
-

-
-
-
-
- Нравится: 35
-
-
-
- Варварва Н.
- Нарисовала картину, посмотрите какая красивая
-
-
- 3 часа назад
-
-
- -
-
-
-
-
-

-
-
-
-
- Нравится: 0
-
-
-
- Варварва Н.
- Голова
-
-
- 8 дней назад
-
-
-
-
`;
+
+
+
+ ${posts.map(post => `
+ -
+
+
+

+
+
+
+
+ Нравится: ${post.likes.map(like => `${like.name} `).join('')}
+
+
+
+ ${post.user.name}
+ ${post.description}
+
+
+ ${dateFns.formatDistanceToNow(new Date(post.createdAt), { addSuffix: true, locale: dateFns.locale.ru })}
+
+
+ `).join('')}
+
+
`;
appEl.innerHTML = appHtml;
@@ -106,4 +52,39 @@ export function renderPostsPageComponent({ appEl }) {
});
});
}
+
+ for (let likeButton of document.querySelectorAll(".like-button")) {
+ likeButton.addEventListener("click", () => {
+ const postId = likeButton.dataset.postId;
+ const post = posts.find(post => post.id === postId);
+ const isLiked = post.isLiked;
+
+ if (isLiked) {
+ unlikePost({ postId, token: getToken() }).then(() => {
+ // Обновляем локально список постов после успешного отзыва лайка
+ post.isLiked = false;
+ post.likes = post.likes.filter(like => like.id !== user.id);
+ renderPostsPageComponent({ appEl });
+ }).catch(error => {
+ console.error("Ошибка отзыва лайка:", error);
+ alert("Ошибка отзыва лайка: " + error.message);
+ });
+ } else {
+ likePost({ postId, token: getToken() }).then(() => {
+ // Обновляем локально список постов после успешного лайка
+ post.isLiked = true;
+ post.likes.push({ id: user.id, name: user.name });
+ renderPostsPageComponent({ appEl });
+ }).catch(error => {
+ console.error("Ошибка лайка:", error);
+ alert("Ошибка лайка: " + error.message);
+ });
+ }
+ });
+ }
}
+
+const getToken = () => {
+ const token = user ? `Bearer ${user.token}` : undefined;
+ return token;
+};
diff --git a/components/upload-image-component.js b/components/upload-image-component.js
index 2bdcdbf3..8cd12873 100644
--- a/components/upload-image-component.js
+++ b/components/upload-image-component.js
@@ -5,54 +5,63 @@ export function renderUploadImageComponent({ element, onImageUrlChange }) {
const render = () => {
element.innerHTML = `
-
- ${
- imageUrl
- ? `
-
-

-
-
- `
- : `
-
+ `
+ }
+
+ `;
const fileInputElement = element.querySelector(".file-upload-input");
- fileInputElement?.addEventListener("change", () => {
- const file = fileInputElement.files[0];
- if (file) {
- const lableEl = document.querySelector(".file-upload-label");
- lableEl.setAttribute("disabled", true);
- lableEl.textContent = "Загружаю файл...";
- uploadImage({ file }).then(({ fileUrl }) => {
- imageUrl = fileUrl;
- onImageUrlChange(imageUrl);
- render();
- });
- }
- });
+ if (fileInputElement) {
+ fileInputElement.addEventListener("change", () => {
+ const file = fileInputElement.files[0];
+ if (file) {
+ const labelEl = element.querySelector(".file-upload-label");
+ labelEl.setAttribute("disabled", true);
+ labelEl.textContent = "Загружаю файл...";
+ uploadImage({ file })
+ .then(({ fileUrl }) => {
+ imageUrl = fileUrl;
+ onImageUrlChange(imageUrl);
+ render(); // Перерисовка компонента с новым URL изображения
+ })
+ .catch(error => {
+ console.error("Ошибка загрузки файла:", error);
+ labelEl.removeAttribute("disabled");
+ labelEl.textContent = "Выберите фото";
+ });
+ }
+ });
+ }
+
+ const removeButtonElement = element.querySelector(".file-upload-remove-button");
- element
- .querySelector(".file-upload-remove-button")
- ?.addEventListener("click", () => {
+ if (removeButtonElement) {
+ removeButtonElement.addEventListener("click", () => {
imageUrl = "";
onImageUrlChange(imageUrl);
- render();
+ render(); // Перерисовка компонента для удаления изображения
});
+ }
};
render();
-}
+}
\ No newline at end of file
diff --git a/components/user-posts-page-component.js b/components/user-posts-page-component.js
new file mode 100644
index 00000000..4e675abb
--- /dev/null
+++ b/components/user-posts-page-component.js
@@ -0,0 +1,83 @@
+import { renderHeaderComponent } from "./header-component.js";
+import { goToPage, user } from "../index.js";
+import { likePost, unlikePost } from "../api.js";
+
+
+export const renderUserPostsPageComponent = ({ appEl, posts }) => {
+ if (!Array.isArray(posts)) {
+ console.error("Posts is not an array or undefined:", posts);
+ posts = [];
+ }
+
+ appEl.innerHTML = `
+
+
+
+ ${posts.map(post => `
+ -
+
+
+

+
+
+
+
+ Нравится: ${post.likes.map(like => `${like.name} `).join('')}
+
+
+
+ ${post.user.name}
+ ${post.description}
+
+
+ ${dateFns.formatDistanceToNow(new Date(post.createdAt), { addSuffix: true, locale: dateFns.locale.ru })}
+
+
+ `).join('')}
+
+
`;
+
+ renderHeaderComponent({
+ element: document.querySelector(".header-container"),
+ });
+
+ for (let likeButton of document.querySelectorAll(".like-button")) {
+ likeButton.addEventListener("click", () => {
+ const postId = likeButton.dataset.postId;
+ const post = posts.find(post => post.id === postId);
+ const isLiked = post.isLiked;
+
+ if (isLiked) {
+ unlikePost({ postId, token: getToken() }).then(() => {
+ // Обновляем локально список постов после успешного отзыва лайка
+ post.isLiked = false;
+ post.likes = post.likes.filter(like => like.id !== user.id);
+ renderUserPostsPageComponent({ appEl, posts }); // Обновляем текущую страницу
+ }).catch(error => {
+ console.error("Ошибка отзыва лайка:", error);
+ alert("Ошибка отзыва лайка: " + error.message);
+ });
+ } else {
+ likePost({ postId, token: getToken() }).then(() => {
+ // Обновляем локально список постов после успешного лайка
+ post.isLiked = true;
+ post.likes.push({ id: user.id, name: user.name });
+ renderUserPostsPageComponent({ appEl, posts }); // Обновляем текущую страницу
+ }).catch(error => {
+ console.error("Ошибка лайка:", error);
+ alert("Ошибка лайка: " + error.message);
+ });
+ }
+ });
+ }
+};
+
+const getToken = () => {
+ const token = user ? `Bearer ${user.token}` : undefined;
+ return token;
+};
diff --git a/index.html b/index.html
index 96674b4d..2b4471d3 100644
--- a/index.html
+++ b/index.html
@@ -11,7 +11,8 @@
-
+
+