Skip to content

Commit dab0ca3

Browse files
committed
feat: add server data loading and form submission
1 parent 462870d commit dab0ca3

5 files changed

Lines changed: 157 additions & 6 deletions

File tree

js/api.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
const BASE_URL = 'https://31.javascript.htmlacademy.pro/kekstagram';
2+
3+
const Route = {
4+
GET_DATA: '/data',
5+
SEND_DATA: '/',
6+
};
7+
8+
const ErrorText = {
9+
GET_DATA: 'Не удалось загрузить данные. Попробуйте обновить страницу',
10+
SEND_DATA: 'Не удалось отправить форму. Попробуйте ещё раз',
11+
};
12+
13+
const getData = () =>
14+
fetch(`${BASE_URL}${Route.GET_DATA}`)
15+
.then((response) => {
16+
if (!response.ok) {
17+
throw new Error(ErrorText.GET_DATA);
18+
}
19+
return response.json();
20+
});
21+
22+
const sendData = (body) =>
23+
fetch(`${BASE_URL}${Route.SEND_DATA}`, {
24+
method: 'POST',
25+
body,
26+
})
27+
.then((response) => {
28+
if (!response.ok) {
29+
throw new Error(ErrorText.SEND_DATA);
30+
}
31+
return response.json();
32+
});
33+
34+
export { getData, sendData };

js/full-size-picture.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
import { photos } from './create-array-photos.js';
21
import { clearComments, renderComments } from './render-comments.js';
32

3+
// Хранилище для данных фотографий, загруженных с сервера
4+
let photos = [];
5+
6+
// Устанавливает массив фотографий (вызывается из main.js после загрузки данных)
7+
const setPhotos = (data) => {
8+
photos = data;
9+
};
10+
411
const bigPictureNode = document.querySelector('.big-picture');
512
const bigPictureImgNode = bigPictureNode.querySelector('.big-picture__img').querySelector('img');
613
const likesCountNode = bigPictureNode.querySelector('.likes-count');
@@ -49,4 +56,4 @@ const openBigPicture = (pictureId) => {
4956

5057
bigPictureCancelNode.addEventListener('click', onBigPictureCancelClick);
5158

52-
export {openBigPicture};
59+
export { openBigPicture, setPhotos };

js/main.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
1-
import { photos } from './create-array-photos.js';
21
import { renderThumbnails } from './render-thumbnails.js';
32
import { initUploadPhotoForm } from './upload-photo-form.js';
43
import { initImageEditor } from './image-editor.js';
4+
import { getData } from './api.js';
5+
import { showDataLoadError } from './messages.js';
6+
import { setPhotos } from './full-size-picture.js';
57

6-
renderThumbnails(photos);
8+
// Инициализация формы загрузки и редактора изображений
79
initUploadPhotoForm();
810
initImageEditor();
911

12+
// Загрузка данных с сервера
13+
getData()
14+
.then((photos) => {
15+
setPhotos(photos);
16+
renderThumbnails(photos);
17+
})
18+
.catch((err) => {
19+
showDataLoadError(err.message);
20+
});
21+

js/messages.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Модуль для показа сообщений об успехе/ошибке
2+
3+
const ALERT_SHOW_TIME = 5000;
4+
5+
const dataErrorTemplate = document.querySelector('#data-error').content.querySelector('.data-error');
6+
const successTemplate = document.querySelector('#success').content.querySelector('.success');
7+
const errorTemplate = document.querySelector('#error').content.querySelector('.error');
8+
9+
10+
// Показывает сообщение об ошибке загрузки данных
11+
12+
const showDataLoadError = () => {
13+
const dataErrorElement = dataErrorTemplate.cloneNode(true);
14+
document.body.appendChild(dataErrorElement);
15+
16+
setTimeout(() => {
17+
dataErrorElement.remove();
18+
}, ALERT_SHOW_TIME);
19+
};
20+
21+
22+
// Создает и показывает модальное сообщение (успех или ошибка)
23+
24+
const showMessage = (template, buttonClass) => {
25+
const messageElement = template.cloneNode(true);
26+
document.body.appendChild(messageElement);
27+
28+
const closeButton = messageElement.querySelector(buttonClass);
29+
30+
const closeMessage = () => {
31+
messageElement.remove();
32+
document.removeEventListener('keydown', onEscKeydown);
33+
document.removeEventListener('click', onOutsideClick);
34+
};
35+
36+
function onEscKeydown(evt) {
37+
if (evt.key === 'Escape') {
38+
evt.preventDefault();
39+
closeMessage();
40+
}
41+
}
42+
43+
function onOutsideClick(evt) {
44+
if (evt.target === messageElement) {
45+
closeMessage();
46+
}
47+
}
48+
49+
closeButton.addEventListener('click', closeMessage);
50+
document.addEventListener('keydown', onEscKeydown);
51+
document.addEventListener('click', onOutsideClick);
52+
};
53+
54+
const showSuccessMessage = () => {
55+
showMessage(successTemplate, '.success__button');
56+
};
57+
58+
const showErrorMessage = () => {
59+
showMessage(errorTemplate, '.error__button');
60+
};
61+
62+
export { showDataLoadError, showSuccessMessage, showErrorMessage };

js/upload-photo-form.js

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,14 @@ import {
66
} from './check-hashtag-validity.js';
77

88
import { resetImageEditor } from './image-editor.js';
9+
import { sendData } from './api.js';
10+
import { showSuccessMessage, showErrorMessage } from './messages.js';
911

1012
const MAX_COMMENT_LENGTH = 140;
13+
const SubmitButtonText = {
14+
IDLE: 'Опубликовать',
15+
SENDING: 'Публикую...',
16+
};
1117

1218
const bodyNode = document.body;
1319
const uploadFormNode = document.querySelector('.img-upload__form');
@@ -16,6 +22,7 @@ const uploadOverlayNode = uploadFormNode.querySelector('.img-upload__overlay');
1622
const uploadCancelButtonNode = uploadFormNode.querySelector('#upload-cancel');
1723
const hashtagsInputNode = uploadFormNode.querySelector('.text__hashtags');
1824
const descriptionInputNode = uploadFormNode.querySelector('.text__description');
25+
const submitButtonNode = uploadFormNode.querySelector('.img-upload__submit');
1926

2027
const pristine = new Pristine(uploadFormNode, {
2128
classTo: 'img-upload__field-wrapper',
@@ -28,6 +35,13 @@ const isEscapeKey = (evt) => evt.key === 'Escape';
2835

2936
const hasValidCommentLength = (value) => value.length <= MAX_COMMENT_LENGTH;
3037

38+
const toggleSubmitButton = (isDisabled) => {
39+
submitButtonNode.disabled = isDisabled;
40+
submitButtonNode.textContent = isDisabled
41+
? SubmitButtonText.SENDING
42+
: SubmitButtonText.IDLE;
43+
};
44+
3145
const resetUploadPhotoForm = () => {
3246
uploadFormNode.reset();
3347
uploadFileControl.value = '';
@@ -74,11 +88,32 @@ const onUploadCancelButtonClick = (evt) => {
7488
};
7589

7690
const onUploadFormSubmit = (evt) => {
77-
if (!pristine.validate()) {
78-
evt.preventDefault();
91+
evt.preventDefault();
92+
93+
const isValid = pristine.validate();
94+
95+
if (isValid) {
96+
toggleSubmitButton(true);
97+
98+
sendData(new FormData(evt.target))
99+
.then(() => {
100+
closeUploadPhotoForm();
101+
showSuccessMessage();
102+
})
103+
.catch(() => {
104+
showErrorMessage();
105+
})
106+
.finally(() => {
107+
toggleSubmitButton(false);
108+
});
79109
}
80110
};
81111

112+
const onUploadFormReset = (evt) => {
113+
evt.preventDefault();
114+
closeUploadPhotoForm();
115+
};
116+
82117
pristine.addValidator(
83118
hashtagsInputNode,
84119
hasValidHashtagFormat,
@@ -113,6 +148,7 @@ const initUploadPhotoForm = () => {
113148
uploadFileControl.addEventListener('change', onUploadFileControlChange);
114149
uploadCancelButtonNode.addEventListener('click', onUploadCancelButtonClick);
115150
uploadFormNode.addEventListener('submit', onUploadFormSubmit);
151+
uploadFormNode.addEventListener('reset', onUploadFormReset);
116152
hashtagsInputNode.addEventListener('keydown', stopEscapePropagation);
117153
descriptionInputNode.addEventListener('keydown', stopEscapePropagation);
118154
};

0 commit comments

Comments
 (0)