diff --git a/index.html b/index.html index 7f1484e..fce00b9 100644 --- a/index.html +++ b/index.html @@ -7,61 +7,8 @@ -
- -
- - -
- -
-
-
+ +
Загрузка ...
diff --git a/index.js b/index.js index 3245e86..463e019 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,3 @@ -import { fetchGetComments } from './modules/fetchGetComments.js'; -import { addClickBtnAddComment } from './modules/eventsBtnAddComment.js'; +import { renderComments } from './modules/renderComments.js'; -const API = 'https://wedev-api.sky.pro/api/v1/arusskov/comments'; - -fetchGetComments(API); -addClickBtnAddComment(API); +renderComments(); diff --git a/modules/Login.js b/modules/Login.js new file mode 100644 index 0000000..8726939 --- /dev/null +++ b/modules/Login.js @@ -0,0 +1,29 @@ +const hostLogin = 'https://wedev-api.sky.pro/api/user/login'; + +export function Login(login, password) { + return fetch(hostLogin, { + method: 'POST', + body: JSON.stringify({ login, password }), + }) + .then((response) => { + if (response.status === 201) { + return response.json(); + } else { + if (response.status === 400) { + throw new Error('400'); + } else { + throw new Error('Что то пошло не так'); + } + } + }) + .catch((error) => { + switch (error.message) { + case '400': + alert('Не верный логин или пароль'); + break; + default: + alert('Что то пошло не так'); + break; + } + }); +} diff --git a/modules/api.js b/modules/api.js new file mode 100644 index 0000000..20333ca --- /dev/null +++ b/modules/api.js @@ -0,0 +1,54 @@ +import { user } from './user.js'; + +const host = 'https://wedev-api.sky.pro/api/v2/avrusskov-test/comments'; + +export function getComments() { + return fetch(host, { method: 'GET' }).then((response) => { + return response.json(); + }); +} + +export function getCommentsAuthorazation() { + return fetch(host, { + method: 'GET', + headers: { Authorization: `Bearer ${user.token}` }, + }).then((response) => { + return response.json(); + }); +} + +export function postComment(newComment) { + return fetch(host, { + method: 'POST', + headers: { Authorization: `Bearer ${user.token}` }, + body: JSON.stringify(newComment), + }) + .then((responce) => { + if (responce.status === 201) { + return; + } else { + if (responce.status === 400) { + throw new Error('400'); + } + } + }) + .catch((error) => { + switch (error.message) { + case '400': + alert('Имя и комментарий должны быть не короче 3 символов'); + break; + default: + alert('Кажется, у вас сломался интернет, попробуйте позже'); + break; + } + }); +} + +export function updateLike(id) { + return fetch(`${host}/${id}/toggle-like`, { + method: 'POST', + headers: { Authorization: `Bearer ${user.token}` }, + }).then((response) => { + return response.json(); + }); +} diff --git a/modules/eventsBtnAddComment.js b/modules/eventsBtnAddComment.js index ac6a27b..0f06f03 100644 --- a/modules/eventsBtnAddComment.js +++ b/modules/eventsBtnAddComment.js @@ -1,23 +1,13 @@ -import { replaceSymbol } from './replace.js'; -import { fetchGetComments } from './fetchGetComments.js'; +import { removeClassError, replaceSymbol } from './helpers.js'; +import { postComment } from './api.js'; +import { renderComments } from './renderComments.js'; -let btnWrite = document.querySelector('.add-form-button'); -let inputName = document.querySelector('.add-form-name'); -let inputText = document.querySelector('.add-form-text'); -const formAddComment = document.querySelector('.add-form'); -const container = document.querySelector('.container'); +async function clickAddComment() { + const inputText = document.querySelector('.add-form-text'); + const formAddComment = document.querySelector('.add-form'); + const container = document.querySelector('.container'); -function removeClassError(input) { - input.classList.remove('input-error'); -} - -function clickAddComment(API) { - if (inputName.value === '' || inputText.value === '') { - if (inputName.value === '') { - inputName.classList.add('input-error'); - - setTimeout(() => removeClassError(inputName), 2000); - } + if (inputText.value === '') { if (inputText.value === '') { inputText.classList.add('input-error'); @@ -27,63 +17,17 @@ function clickAddComment(API) { return; } - const newComment = { - text: replaceSymbol(inputText.value), - name: replaceSymbol(inputName.value), - forceError: true, - }; - formAddComment.style.display = 'none'; const loaderText = document.createElement('p'); loaderText.textContent = 'Комментарий добавляется'; container.appendChild(loaderText); - let isCrashServer = false; - - fetch(API, { - method: 'POST', - body: JSON.stringify(newComment), - }) - .then((responce) => { - if (responce.status === 201) { - inputName.value = ''; - inputText.value = ''; - - return fetchGetComments(API); - } else { - if (responce.status === 400) { - throw new Error('400'); - } - - if (responce.status === 500) { - isCrashServer = true; - clickAddComment(API); - } - } - }) - .catch((error) => { - switch (error.message) { - case '400': - alert('Имя и комментарий должны быть не короче 3 символов'); - break; - case '500': - alert('Сервер сломался, попробуй позже'); - break; - default: - alert('Кажется, у вас сломался интернет, попробуйте позже'); - break; - } - }) - .finally(() => { - container.removeChild(loaderText); - - if (!isCrashServer) { - formAddComment.style.display = 'flex'; - } - }); + await postComment({ text: replaceSymbol(inputText.value) }); + renderComments(); } -export function addClickBtnAddComment(API) { - btnWrite.addEventListener('click', () => clickAddComment(API)); +export function addClickBtnAddComment() { + const btnWrite = document.getElementById('write-button'); + btnWrite.addEventListener('click', clickAddComment); } diff --git a/modules/eventsComment.js b/modules/eventsComment.js index f6135c9..4c5cc91 100644 --- a/modules/eventsComment.js +++ b/modules/eventsComment.js @@ -1,13 +1,7 @@ -import { renderComments } from './render.js'; +import { updateLike } from './api.js'; import { comments } from './comments.js'; - -function delay(interval = 300) { - return new Promise((resolve) => { - setTimeout(() => { - resolve(); - }, interval); - }); -} +import { renderComments } from './renderComments.js'; +import { user } from './user.js'; export function addClickBtnLike() { const arrayBtnLike = document.querySelectorAll('.like-button'); @@ -16,18 +10,18 @@ export function addClickBtnLike() { btnLike.addEventListener('click', (event) => { event.stopPropagation(); - btnLike.classList.add('loading-like'); - console.log(btnLike.classList); + if (Object.keys(user).length !== 0) { + const index = btnLike.dataset.index; - const index = btnLike.dataset.index; + updateLike(comments[index].id).then((data) => { + comments[index].likes = data.result.likes; + comments[index].isLiked = data.result.isLiked; - delay(2000).then(() => { - comments[index].isLiked - ? comments[index].likes-- - : comments[index].likes++; - comments[index].isLiked = !comments[index].isLiked; - renderComments(); - }); + renderComments(); + }); + } else { + alert('Нужно авторизоваться'); + } }); } } diff --git a/modules/fetchGetComments.js b/modules/fetchGetComments.js deleted file mode 100644 index 8048940..0000000 --- a/modules/fetchGetComments.js +++ /dev/null @@ -1,13 +0,0 @@ -import { renderComments } from './render.js'; -import { updateComments } from './comments.js'; - -export function fetchGetComments(API) { - return fetch(API, { method: 'GET' }) - .then((response) => { - return response.json(); - }) - .then((data) => { - updateComments(data.comments); - renderComments(); - }); -} diff --git a/modules/replace.js b/modules/helpers.js similarity index 55% rename from modules/replace.js rename to modules/helpers.js index a91d0e1..de232e5 100644 --- a/modules/replace.js +++ b/modules/helpers.js @@ -1,3 +1,7 @@ export function replaceSymbol(text) { return text.replaceAll('<', '˂').replaceAll('>', '˃'); } + +export function removeClassError(input) { + input.classList.remove('input-error'); +} diff --git a/modules/localStorage.js b/modules/localStorage.js new file mode 100644 index 0000000..05cd72e --- /dev/null +++ b/modules/localStorage.js @@ -0,0 +1,30 @@ +import { updateUser } from './user.js'; + +export function setLocalStorage(user) { + for (let key in user) { + localStorage.setItem(key, user[key]); + } +} + +export function getLocalStorage() { + const newUser = {}; + newUser['_id'] = localStorage.getItem('_id'); + newUser['imageUrl'] = localStorage.getItem('imageUrl'); + newUser['login'] = localStorage.getItem('login'); + newUser['name'] = localStorage.getItem('name'); + newUser['password'] = localStorage.getItem('password'); + newUser['token'] = localStorage.getItem('token'); + + return newUser; +} + +export function clearLocalStorage() { + localStorage.removeItem('_id'); + localStorage.removeItem('imageUrl'); + localStorage.removeItem('login'); + localStorage.removeItem('name'); + localStorage.removeItem('password'); + localStorage.removeItem('token'); + + updateUser({}); +} diff --git a/modules/registration.js b/modules/registration.js new file mode 100644 index 0000000..1677ecf --- /dev/null +++ b/modules/registration.js @@ -0,0 +1,29 @@ +const hostRegistration = 'https://wedev-api.sky.pro/api/user'; + +export function Registration(name, login, password) { + return fetch(hostRegistration, { + method: 'POST', + body: JSON.stringify({ name, login, password }), + }) + .then((response) => { + if (response.status === 201) { + return response.json(); + } else { + if (response.status === 400) { + throw new Error('400'); + } else { + throw new Error('Что то пошло не так'); + } + } + }) + .catch((error) => { + switch (error.message) { + case '400': + alert('Пользователь с таким логином уже есть'); + break; + default: + alert('Что то пошло не так'); + break; + } + }); +} diff --git a/modules/render.js b/modules/render.js deleted file mode 100644 index b1d9ae2..0000000 --- a/modules/render.js +++ /dev/null @@ -1,37 +0,0 @@ -import { comments } from './comments.js'; -import { addClickBtnLike, addClickComment } from './eventsComment.js'; -import { formatDate } from './date.js'; - -export function renderComments() { - const listComment = document.querySelector('.comments'); - - const htmlComments = comments - .map((comment, index) => { - return ` -
  • -
    -
    ${comment.author.name}
    -
    ${formatDate(comment.date)}
    -
    -
    -
    -
    -
    - ${comment.text.replaceAll('\n', '
    ')} -
    -
    - -
  • `; - }) - .join(''); - - listComment.innerHTML = htmlComments; - - addClickBtnLike(); - addClickComment(); -} diff --git a/modules/renderComments.js b/modules/renderComments.js new file mode 100644 index 0000000..d2317e4 --- /dev/null +++ b/modules/renderComments.js @@ -0,0 +1,87 @@ +import { comments, updateComments } from './comments.js'; + +import { renderForm } from './renderForm.js'; +import { renderLogin } from './renderLogin.js'; +import { renderRegistration } from './renderRegistration.js'; + +import { addClickBtnLike, addClickComment } from './eventsComment.js'; +import { formatDate } from './date.js'; +import { getComments, getCommentsAuthorazation } from './api.js'; +import { renderHeader } from './renderHeader.js'; +import { getLocalStorage } from './localStorage.js'; +import { updateUser } from './user.js'; + +export async function renderComments() { + if (localStorage.getItem('token') !== null) { + updateUser(getLocalStorage()); + + await getCommentsAuthorazation().then((data) => { + updateComments(data.comments); + }); + + renderHeader(); + } else { + await getComments().then((data) => { + updateComments(data.comments); + }); + } + + const app = document.getElementById('app'); + + const htmlComments = comments + .map((comment, index) => { + return ` +
  • +
    +
    ${comment.author.name}
    +
    ${formatDate(comment.date)}
    +
    +
    +
    +
    +
    + ${comment.text.replaceAll('\n', '
    ')} +
    +
    + +
  • `; + }) + .join(''); + + app.innerHTML = ` + + `; + + if (localStorage.getItem('token') === null) { + const app = document.getElementById('app'); + + const login = document.createElement('button'); + login.classList.add('add-form-button'); + login.textContent = 'Чтобы добавить комментарий, авторизуйтесь'; + login.addEventListener('click', () => { + renderLogin(); + }); + + const registaration = document.createElement('button'); + registaration.classList.add('add-form-button'); + registaration.textContent = 'Регистрация'; + registaration.addEventListener('click', () => { + renderRegistration(); + }); + + app.appendChild(login); + app.appendChild(registaration); + } else { + renderForm(); + addClickComment(); + } + + addClickBtnLike(); +} diff --git a/modules/renderForm.js b/modules/renderForm.js new file mode 100644 index 0000000..88a15a4 --- /dev/null +++ b/modules/renderForm.js @@ -0,0 +1,32 @@ +import { addClickBtnAddComment } from './eventsBtnAddComment.js'; +import { user } from './user.js'; + +export function renderForm() { + const app = document.getElementById('app'); + const form = document.createElement('div'); + + form.innerHTML = ` +
    + + +
    + +
    +
    + `; + + app.appendChild(form); + + addClickBtnAddComment(); +} diff --git a/modules/renderHeader.js b/modules/renderHeader.js new file mode 100644 index 0000000..89fa4dd --- /dev/null +++ b/modules/renderHeader.js @@ -0,0 +1,19 @@ +import { clearLocalStorage } from './localStorage.js'; +import { renderComments } from './renderComments.js'; +import { user } from './user.js'; + +export function renderHeader() { + const header = document.getElementById('header'); + + header.innerHTML = ` +

    ${user.name}

    + + `; + + const logoutBtn = document.getElementById('logout'); + logoutBtn.addEventListener('click', () => { + clearLocalStorage(); + header.innerHTML = ''; + renderComments(); + }); +} diff --git a/modules/renderLogin.js b/modules/renderLogin.js new file mode 100644 index 0000000..b6e161b --- /dev/null +++ b/modules/renderLogin.js @@ -0,0 +1,63 @@ +import { removeClassError } from './helpers.js'; +import { setLocalStorage } from './localStorage.js'; +import { Login } from './login.js'; +import { renderComments } from './renderComments.js'; +import { updateUser } from './user.js'; + +export function renderLogin() { + window.scrollTo(0, 0); + + const app = document.getElementById('app'); + + app.innerHTML = ` +
    + + +
    + + +
    +
    `; + + const loginInput = document.getElementById('login-input'); + const passwordInput = document.getElementById('password-input'); + const loginBtn = document.getElementById('login-btn'); + const backBtn = document.getElementById('back-btn'); + + loginBtn.addEventListener('click', () => { + if (loginInput.value === '' || passwordInput.value === '') { + if (loginInput.value === '') { + loginInput.classList.add('input-error'); + + setTimeout(() => removeClassError(loginInput), 2000); + } + + if (passwordInput.value === '') { + passwordInput.classList.add('input-error'); + + setTimeout(() => removeClassError(passwordInput), 2000); + } + + return; + } + Login(loginInput.value, passwordInput.value).then((data) => { + setLocalStorage(data.user); + updateUser(data.user); + renderComments(); + }); + }); + + backBtn.addEventListener('click', () => { + renderComments(); + }); +} diff --git a/modules/renderRegistration.js b/modules/renderRegistration.js new file mode 100644 index 0000000..b94599d --- /dev/null +++ b/modules/renderRegistration.js @@ -0,0 +1,84 @@ +import { removeClassError } from './helpers.js'; +import { setLocalStorage } from './localStorage.js'; +import { Registration } from './registration.js'; +import { renderComments } from './renderComments.js'; +import { updateUser } from './user.js'; + +export function renderRegistration() { + window.scrollTo(0, 0); + + const app = document.getElementById('app'); + + app.innerHTML = ` +
    + + + +
    + + +
    +
    `; + + const nameInput = document.getElementById('name-input'); + const loginInput = document.getElementById('login-input'); + const passwordInput = document.getElementById('password-input'); + const registrationBtn = document.getElementById('registration-btn'); + const backBtn = document.getElementById('back-btn'); + + registrationBtn.addEventListener('click', () => { + if ( + loginInput.value === '' || + passwordInput.value === '' || + nameInput.value === '' + ) { + if (nameInput.value === '') { + nameInput.classList.add('input-error'); + + setTimeout(() => removeClassError(nameInput), 2000); + } + if (loginInput.value === '') { + loginInput.classList.add('input-error'); + + setTimeout(() => removeClassError(loginInput), 2000); + } + + if (passwordInput.value === '') { + passwordInput.classList.add('input-error'); + + setTimeout(() => removeClassError(passwordInput), 2000); + } + + return; + } + + Registration( + nameInput.value, + loginInput.value, + passwordInput.value, + ).then((data) => { + setLocalStorage(data.user); + updateUser(data.user); + renderComments(); + }); + }); + + backBtn.addEventListener('click', () => { + renderComments(); + }); +} diff --git a/modules/user.js b/modules/user.js new file mode 100644 index 0000000..1ba4d6c --- /dev/null +++ b/modules/user.js @@ -0,0 +1,5 @@ +export let user = {}; + +export function updateUser(newUser) { + user = newUser; +} diff --git a/styles.css b/styles.css index 21d5e6a..f8f03fe 100644 --- a/styles.css +++ b/styles.css @@ -2,21 +2,6 @@ body { margin: 0; } -@keyframes rotating { - from { - transform: rotate(0deg); - } - 25% { - transform: rotate(30deg); - } - 75% { - transform: rotate(-30deg); - } - to { - transform: rotate(0deg); - } -} - .container { font-family: Helvetica; color: #ffffff; @@ -29,6 +14,25 @@ body { min-height: 100vh; } +.header { + font-family: Helvetica; + color: #ffffff; + display: flex; + flex-direction: row; + justify-content: flex-end; + gap: 30px; + background: #202020; +} + +.header-btn { + font-size: 24px; + padding: 10px 20px; + background-color: #bcec30; + border: none; + border-radius: 18px; + cursor: pointer; +} + .comments, .comment { margin: 0; @@ -106,10 +110,6 @@ body { background-image: url("data:image/svg+xml,%3Csvg width='22' height='20' viewBox='0 0 22 20' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M15.95 0C14.036 0 12.199 0.882834 11 2.26703C9.801 0.882834 7.964 0 6.05 0C2.662 0 0 2.6267 0 5.99455C0 10.1035 3.74 13.4714 9.405 18.5613L11 20L12.595 18.5613C18.26 13.4714 22 10.1035 22 5.99455C22 2.6267 19.338 0 15.95 0Z' fill='%23BCEC30'/%3E%3C/svg%3E"); } -.loading-like { - animation: rotating 2s linear infinite; -} - .add-form { padding: 20px; margin-top: 48px; @@ -134,6 +134,20 @@ body { padding: 11px 22px; } +.add-form-name_login, +.add-form-text { + font-size: 16px; + font-family: Helvetica; + border-radius: 8px; + border: none; +} + +.add-form-name_login { + width: 300px; + padding: 11px 22px; + margin-top: 12px; +} + .add-form-text { margin-top: 12px; padding: 22px; @@ -145,6 +159,12 @@ body { justify-content: flex-end; } +.add-form-login { + display: flex; + flex-direction: row; + justify-content: space-between; +} + .add-form-button { margin-top: 24px; font-size: 24px;