Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.0 #106

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open

1.0 #106

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ MVP аналога популярной соц. сети для обмена ф

## Ссылка на приложение:

https::
https:: https://github.com/GlebkaF/webdev-cw-instapro/pull/104

## Первоначальная оценка

ХХХХ часов
10 часов

## Фактически затраченное время
15 часов

YYYY часов

##
Добавлена "фича" - на странице пользователя появилась, отдельно, большая аватрка пользователя, его юзернейм и информационное поле, в котором указано когда пользователь добавил последний пост. приемр : "Последний пост был: 5 минут назад"
57 changes: 56 additions & 1 deletion api.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,32 @@
// Замени на свой, чтобы получить независимый от других набор данных.

// "боевая" версия инстапро лежит в ключе prod
const personalKey = "prod";
const personalKey = "pro228";
const baseHost = "https://webdev-hw-api.vercel.app";
const postsHost = `${baseHost}/api/v1/${personalKey}/instapro`;

export function addPosts({ imageUrl, description, token }) {
return fetch(postsHost, {
method: "POST",
headers: {
Authorization: token,
},
body: JSON.stringify({
imageUrl, description
})
})
.then((response) => {
if (response.status === 401) {
throw new Error("Нет авторизации");
}

return response.json();
})
.then((data) => {
return data;
});
}

export function getPosts({ token }) {
return fetch(postsHost, {
method: "GET",
Expand All @@ -23,6 +46,22 @@ export function getPosts({ token }) {
});
}

export async function getUserPosts({ userId, token }) {
const response = await fetch(`${postsHost}/user-posts/${userId}`, {
method: 'GET',
headers: {
Authorization: token,
}
});
if (!response.ok) {
throw new Error('Ошибка при получении постов пользователя');
}
const data = await response.json();
return data.posts;
}



// https://github.com/GlebkaF/webdev-hw-api/blob/main/pages/api/user/README.md#%D0%B0%D0%B2%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%D1%81%D1%8F
export function registerUser({ login, password, name, imageUrl }) {
return fetch(baseHost + "/api/user", {
Expand Down Expand Up @@ -68,3 +107,19 @@ export function uploadImage({ file }) {
return response.json();
});
}
// это в конец файла api.js
export async function toggleLike(postId, isLiked, token) {
const url = `${postsHost}/${postId}/${isLiked ? 'dislike' : 'like'}`;
const response = await fetch(url, {
method: 'POST',
headers: {
Authorization: token,
},
});
if (!response.ok) {
throw new Error('Ошибка при изменении лайка');
}
return response.json();
}


56 changes: 47 additions & 9 deletions components/add-post-page-component.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,61 @@


import { renderHeaderComponent } from "./header-component.js";
import { renderUploadImageComponent } from "./upload-image-component.js";

export function renderAddPostPageComponent({ appEl, onAddPostClick }) {
let imageUrl = " ";
const render = () => {
// TODO: Реализовать страницу добавления поста
// TODO: Реализовать добавления поста в апи
const appHtml = `
<div class="page-container">
<div class="header-container"></div>
Cтраница добавления поста
<button class="button" id="add-button">Добавить</button>
</div>
`;
<div class="header-container"></div>

<div class="form">
<h3 class="form-title">Добавить пост</h3>
<div class="form-inputs">
<div class="upload-image-container">

</div>
<label>
Опишите фотографию:
<textarea class="input textarea" rows="4"></textarea>
</label>
<button class="button" id="add-button">Добавить</button>
</div>
</div>
</div>
`;

appEl.innerHTML = appHtml;

renderHeaderComponent({
element: document.querySelector(".header-container"),
});

const uploadImageContainer = appEl.querySelector(".upload-image-container");

if (uploadImageContainer) {
renderUploadImageComponent({
element: appEl.querySelector(".upload-image-container"),
onImageUrlChange(newImageUrl) {
imageUrl = newImageUrl;
},
});
}

document.getElementById("add-button").addEventListener("click", () => {
const description = document.querySelector(".textarea").value.trim();
if (!description || !imageUrl.trim()) {
alert("Добавьте изображение или текст");
return;
}
onAddPostClick({
description: "Описание картинки",
imageUrl: "https://image.png",
description,
imageUrl
});
});
};

render();
}
}
170 changes: 70 additions & 100 deletions components/posts-page-component.js
Original file line number Diff line number Diff line change
@@ -1,109 +1,79 @@
import { USER_POSTS_PAGE } from "../routes.js";
import { USER_POSTS_PAGE, POSTS_PAGE, AUTH_PAGE } from "../routes.js"; // Добавлен импорт POSTS_PAGE
import { renderHeaderComponent } from "./header-component.js";
import { posts, goToPage } from "../index.js";
import { getPosts, toggleLike } from "../api.js";
import { goToPage, posts, getToken, user } from "../index.js"; // Импорт функции getToken

export function renderPostsPageComponent({ appEl }) {
// TODO: реализовать рендер постов из api
console.log("Актуальный список постов:", posts);
console.log("Актуальный список постов:", posts);

/**
* TODO: чтобы отформатировать дату создания поста в виде "19 минут назад"
* можно использовать https://date-fns.org/v2.29.3/docs/formatDistanceToNow
*/
const appHtml = `
<div class="page-container">
<div class="header-container"></div>
<ul class="posts">
<li class="post">
<div class="post-header" data-user-id="642d00329b190443860c2f31">
<img src="https://www.imgonline.com.ua/examples/bee-on-daisy.jpg" class="post-header__user-image">
<p class="post-header__user-name">Иван Иваныч</p>
</div>
<div class="post-image-container">
<img class="post-image" src="https://www.imgonline.com.ua/examples/bee-on-daisy.jpg">
</div>
<div class="post-likes">
<button data-post-id="642d00579b190443860c2f32" class="like-button">
<img src="./assets/images/like-active.svg">
</button>
<p class="post-likes-text">
Нравится: <strong>2</strong>
</p>
</div>
<p class="post-text">
<span class="user-name">Иван Иваныч</span>
Ромашка, ромашка...
</p>
<p class="post-date">
19 минут назад
</p>
</li>
<li class="post">
<div class="post-header" data-user-id="6425602ce156b600f7858df2">
<img src="https://storage.yandexcloud.net/skypro-webdev-homework-bucket/1680601502867-%25C3%2590%25C2%25A1%25C3%2590%25C2%25BD%25C3%2590%25C2%25B8%25C3%2590%25C2%25BC%25C3%2590%25C2%25BE%25C3%2590%25C2%25BA%2520%25C3%2591%25C2%258D%25C3%2590%25C2%25BA%25C3%2591%25C2%2580%25C3%2590%25C2%25B0%25C3%2590%25C2%25BD%25C3%2590%25C2%25B0%25202023-04-04%2520%25C3%2590%25C2%25B2%252014.04.29.png" class="post-header__user-image">
<p class="post-header__user-name">Варварва Н.</p>
</div>


<div class="post-image-container">
<img class="post-image" src="https://storage.yandexcloud.net/skypro-webdev-homework-bucket/1680670675451-%25C3%2590%25C2%25A1%25C3%2590%25C2%25BD%25C3%2590%25C2%25B8%25C3%2590%25C2%25BC%25C3%2590%25C2%25BE%25C3%2590%25C2%25BA%2520%25C3%2591%25C2%258D%25C3%2590%25C2%25BA%25C3%2591%25C2%2580%25C3%2590%25C2%25B0%25C3%2590%25C2%25BD%25C3%2590%25C2%25B0%25202023-03-31%2520%25C3%2590%25C2%25B2%252012.51.20.png">
</div>
<div class="post-likes">
<button data-post-id="642cffed9b190443860c2f30" class="like-button">
<img src="./assets/images/like-not-active.svg">
</button>
<p class="post-likes-text">
Нравится: <strong>35</strong>
</p>
</div>
<p class="post-text">
<span class="user-name">Варварва Н.</span>
Нарисовала картину, посмотрите какая красивая
</p>
<p class="post-date">
3 часа назад
</p>
</li>
<li class="post">
<div class="post-header" data-user-id="6425602ce156b600f7858df2">
<img src="https://storage.yandexcloud.net/skypro-webdev-homework-bucket/1680601502867-%25C3%2590%25C2%25A1%25C3%2590%25C2%25BD%25C3%2590%25C2%25B8%25C3%2590%25C2%25BC%25C3%2590%25C2%25BE%25C3%2590%25C2%25BA%2520%25C3%2591%25C2%258D%25C3%2590%25C2%25BA%25C3%2591%25C2%2580%25C3%2590%25C2%25B0%25C3%2590%25C2%25BD%25C3%2590%25C2%25B0%25202023-04-04%2520%25C3%2590%25C2%25B2%252014.04.29.png" class="post-header__user-image">
<p class="post-header__user-name">Варварва Н.</p>
</div>


<div class="post-image-container">
<img class="post-image" src="https://leonardo.osnova.io/97a160ca-76b6-5cba-87c6-84ef29136bb3/">
</div>
<div class="post-likes">
<button data-post-id="642cf82e9b190443860c2f2b" class="like-button">
<img src="./assets/images/like-not-active.svg">
</button>
<p class="post-likes-text">
Нравится: <strong>0</strong>
</p>
</div>
<p class="post-text">
<span class="user-name">Варварва Н.</span>
Голова
</p>
<p class="post-date">
8 дней назад
</p>
</li>
</ul>
</div>`;
const formatDistanceToNow = (date) => {
const now = new Date();
const diff = Math.abs(now - date);
const minutes = Math.floor(diff / 60000);
if (minutes < 60) return `${minutes} минут назад`;
const hours = Math.floor(minutes / 60);
if (hours < 24) return `${hours} часов назад`;
const days = Math.floor(hours / 24);
return `${days} дней назад`;
};

appEl.innerHTML = appHtml;
const postsHtml = posts.map(post => `
<li class="post">
<div class="post-header" data-user-id="${post.user.id}">
<img src="${post.user.imageUrl}" class="post-header__user-image">
<p class="post-header__user-name">${post.user.name}</p>
</div>
<div class="post-image-container">
<img class="post-image" src="${post.imageUrl}">
</div>
<div class="post-likes">
<button data-post-id="${post.id}" class="like-button">
<img src="${post.isLiked ? './assets/images/like-active.svg' : './assets/images/like-not-active.svg'}">
</button>
<p class="post-likes-text">
Нравится: <strong>${post.likes.length}</strong>
</p>
</div>
<p class="post-text">
<span class="user-name">${post.user.name}</span>
${post.description}
</p>
<p class="post-date">
${formatDistanceToNow(new Date(post.createdAt))}
</p>
</li>
`).join('');

renderHeaderComponent({
element: document.querySelector(".header-container"),
});
const appHtml = `
<div class="page-container">
<div class="header-container"></div>
<ul class="posts">
${postsHtml}
</ul>
</div>
`;

for (let userEl of document.querySelectorAll(".post-header")) {
userEl.addEventListener("click", () => {
goToPage(USER_POSTS_PAGE, {
userId: userEl.dataset.userId,
appEl.innerHTML = appHtml;

renderHeaderComponent({
element: document.querySelector(".header-container"),
});

document.querySelectorAll(".post-header").forEach(userEl => {
userEl.addEventListener("click", () => {
goToPage(USER_POSTS_PAGE, { userId: userEl.dataset.userId });
});
});

document.querySelectorAll(".like-button").forEach(likeButton => {
likeButton.addEventListener("click", async () => {
if (!user) {
return goToPage(AUTH_PAGE); // Перенаправление на страницу авторизации
}
const postId = likeButton.dataset.postId;
const post = posts.find(post => post.id === postId);
await toggleLike(postId, post.isLiked, getToken());
goToPage(POSTS_PAGE); // Обновляем страницу после изменения лайка
});
});
}
}
}
Loading