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

Added comments to posts #4

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
1 change: 0 additions & 1 deletion src/components/App/App.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react';
import logo from '../../logo.svg';
import { UserPage } from '../../containers/UserPage/UserPage';

import './App.css';
Expand Down
14 changes: 14 additions & 0 deletions src/components/CommentListItem/CommentListItem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';

const CN = 'post';

export const CommentListItem = (props) => {
const { item } = props;

return (
<div className={`${CN}__comment`}>
<div className={`${CN}__comment__author`}>{item.name}</div>
<div className={`${CN}__comment__text`}>{item.body}</div>
</div>
);
};
2 changes: 1 addition & 1 deletion src/components/List/List.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export class List extends Component {
};

render() {
const { options, selectedOptionId, itemRenderer, className = '', title = '' } = this.props;
const { options, selectedOptionId, itemRenderer, className = '', title = ''} = this.props;
const ItemRenderer = itemRenderer;

return (
Expand Down
15 changes: 15 additions & 0 deletions src/components/LoadingIndicator/LoadingIndicator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from "react";
import './LoadingIndicator.scss'


const CN = 'loading-center';
export const LoadingIndicator = () => {
return (

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty lines on lines 4,8,13 are useless and can be deleted

<div className={CN}>
<div className={`${CN}__loadingspinner`}>
</div>
</div>

)
};
35 changes: 35 additions & 0 deletions src/components/LoadingIndicator/LoadingIndicator.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
.loading-center {
height: 100%;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;

&__loadingspinner{
pointer-events: none;
width: 3em;
height: 3em;
border: 0.5em solid transparent;
border-color: #eee;
border-top-color: #1633dd;
border-radius: 50%;
animation: loadingspin 2s linear infinite;
}


Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty line can be deleted

@keyframes loadingspin {
100% {
transform: rotate(360deg)
}

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty line can be deleted

}
}








179 changes: 85 additions & 94 deletions src/components/Post/Post.js
Original file line number Diff line number Diff line change
@@ -1,115 +1,106 @@
import React, { useState, Component } from "react";
import { Button } from '../Button/Button';
import { PostImage } from '../PostImage/PostImage';
import { accessToken } from '../../constants';
import React, {Component} from "react";
import {accessToken} from '../../constants';
import "./Post.scss";
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Styling import should be the last one on line 7

import {CommentListItem} from "../CommentListItem/CommentListItem";
import {List} from "../List/List";
import {LoadingIndicator} from "../LoadingIndicator/LoadingIndicator";

const postExample = {
"id": "676",
"user_id": "366",
"title": "Et deserunt eos commodi est in atque culpa. Et tempora velit et ut nisi quae et.",
"body": "Rerum eaque et ab. Quas deleniti nostrum qui molestiae deleniti quo. Quia architecto consectetur recusandae eum culpa ea laudantium.\n\nSoluta sequi aut illo laboriosam sed ab qui incidunt. Distinctio asperiores alias laudantium quod neque ducimus et. Esse et qui ab.\n\nDolorum suscipit non omnis voluptates ipsa perspiciatis quia. Odio consequuntur aut vitae unde quia ad ipsum. Temporibus tempore est laborum eaque repellendus soluta iure.\n\nQuisquam cupiditate inventore fuga adipisci rerum blanditiis. Mollitia sed perspiciatis voluptate non impedit velit eum. Quas dolor sint ipsam.",
"_links": {
"self": {
"href": "https://gorest.co.in/public-api/posts/676"
},
"edit": {
"href": "https://gorest.co.in/public-api/posts/676"
}
}
};
// const postExample = {
// "id": "676",
// "user_id": "366",
// "title": "Et deserunt eos commodi est in atque culpa. Et tempora velit et ut nisi quae et.",
// "body": "Rerum eaque et ab. Quas deleniti nostrum qui molestiae deleniti quo. Quia architecto consectetur recusandae eum culpa ea laudantium.\n\nSoluta sequi aut illo laboriosam sed ab qui incidunt. Distinctio asperiores alias laudantium quod neque ducimus et. Esse et qui ab.\n\nDolorum suscipit non omnis voluptates ipsa perspiciatis quia. Odio consequuntur aut vitae unde quia ad ipsum. Temporibus tempore est laborum eaque repellendus soluta iure.\n\nQuisquam cupiditate inventore fuga adipisci rerum blanditiis. Mollitia sed perspiciatis voluptate non impedit velit eum. Quas dolor sint ipsam.",
// "_links": {
// "self": {
// "href": "https://gorest.co.in/public-api/posts/676"
// },
// "edit": {
// "href": "https://gorest.co.in/public-api/posts/676"
// }
// }
// };

const CN = 'post';
export class Post extends Component {

// todo в стейт добавить массив comments, по умолчанию пустой
// todo в стейт добавить флажок isCommentsLoading, который будет означать идет ли загрузка в данный момент, по умолчанию false
// todo в стейт добавить флажок commentsLoaded, который будет означать загрузились ли коментарии
// todo в стейт добавить флажок commentsSectionExpanded, который будет означать отображается ли секция с коментариями в данный момент
// todo в стейт добавить строку error, чтоб хранить значения ошибок, если возникнут

state = {};
export class Post extends Component {
state = {
comments: [],
isCommentsLoading: false,
commentsLoaded: false,
commentsSectionExpanded: false,
error: ""
};

onLoadComments = () => {
// todo достать из props пропсу item, использовать item.id в запросе ниже в строке 39
onLoadComments = () => {
const {item} = this.props;

//todo поменять стейт так, чтоб было понятно что секция с комментариями открыта и началась загрузка
//todo т.е. isCommentsLoading и commentsSectionExpanded станут true
this.setState({
isCommentsLoading: true,
commentsSectionExpanded: true
});

fetch(`https://gorest.co.in/public-api/comments?access-token=${accessToken}&post_id=${1/* todo тут вместо 1 будет id поста т.е. item.id */}`, )
.then(res => {
if (!res.ok) throw Error(res.statusText);
return res.json();
})
.then(data => {
// todo поменять стейт так, чтоб в comments лежали data.result,
// todo лоадинг закончился, т.е. isCommentsLoading будет false, а commentsLoaded станет true (т.е. запрос был выполнен)
})
.catch(error => {
console.log(error);
// todo поменять стейт так, чтоб
// todo лоадинг закончился, т.е. isCommentsLoading будет false, а commentsLoaded станет false (т.е. запрос не был выполнен ввиду ошибки)
// todo в error пойдет значение, error которая вывалилась в результате запроса
// todo и закроем секцию коментариев т.е. commentsSectionExpanded будет false
});
};
fetch(`https://gorest.co.in/public-api/comments?access-token=${accessToken}&post_id=${item.id}`,)
.then(res => {
if (!res.ok) throw Error(res.statusText);
return res.json();
})
.then(data => {
this.setState({
comments: data.result,
isCommentsLoading: false,
commentsLoaded: true
})
})
.catch(error => {
console.log(error);
this.setState({
isCommentsLoading: false,
commentsLoaded: false,
commentsSectionExpanded: false
})
});
};

onShowComments = () => {
// todo если запрос был выполнен раннее, т.е. commentsLoaded = true
// меняем в стейт значение commentsSectionExpanded на противоположное
// делаем return; чтоб остально код этой функции не выполнялся
// т.е. тоглим отображение комментариев

// todo иначе, если запроса не было выполняем его, вызвав метод onLoadComments
const {commentsLoaded, commentsSectionExpanded} = this.state;
if (!commentsLoaded) {
return this.onLoadComments()
} else {
return this.setState({commentsSectionExpanded: !commentsSectionExpanded});
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can skip return here just use
this.onLoadComments()
and
this.setState({commentsSectionExpanded: !commentsSectionExpanded});

}
};

render() {
{/* todo с помощью деструктуризации достать из this.state проперти commentsSectionExpanded, error, isCommentsLoading, comments, commentsLoaded */}
const { item, isClosed } = this.props;
const { id, user_id, title, body } = item;
const {commentsSectionExpanded, error, isCommentsLoading, comments, commentsLoaded} = this.state;
const {item} = this.props;
const {id, title, body} = item;

return (
<div className={`${CN} card `}>
<div className={`${CN}__id`}>id: {id}</div>
<div className="card-body">
<div className="card-title"> {title} </div>
<div className="card-text text">{body}</div>
</div>
return (
<div className={`${CN} card `}>
<div className={`${CN}__id`}>id: {id}</div>
<div className="card-body">
<div className="card-title"> {title} </div>
<div className="card-text text">{body}</div>
</div>

{/* todo создать div который будет выполнять функцию кнопки */}
{/* todo у него должен быть класс, состоящий из комбинации базового класса CN и строки '__link-btn' */}
{/* todo в событие onClick положить метод onShowComments, объявленный выше */}
{/* todo в children этого div должна быть положена строка "Show comments" если флажок commentsSectionExpanded в стейте = true*/}
{/* todo иначе - строка "Hide comments" */}
<div className={`${CN}__link-btn`} onClick={this.onShowComments}>
{commentsSectionExpanded ? "Hide comments" : "Show comments"}
</div>
<div>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This div is not needed and can be deleted

{error && <div>{error}</div>}
</div>

{/* todo создать div который будет выводить ошибку из стейта, если она существует (т.е. не пустая строка) */}
{commentsSectionExpanded && isCommentsLoading &&
<div className={`${CN}__loading`}>
<LoadingIndicator/>
</div>}

{
//todo если секция комментариев открыта, т.е. commentsSectionExpanded = true
// и идет загрузка комментариев, т.е. isCommentsLoading = true
// показываем лоадинг индикатор (можно просто строку с надписью "Loading comments ..." в div)
// если хотите, чтоб выглядело как в видео, добавьте к div класс состоящий из базового класса CN и "__loading"
}
{
//todo если секция комментариев открыта, т.е. commentsSectionExpanded = true
// но НЕ идет загрузка комментариев, т.е. isCommentsLoading = false
// и запрос уже был выполнен т.е. commentsLoaded = true
// и массив comments пустой
// показываем сообщение, что нет результатов (строку с надписью "No comments for this post yet" в div)
// если хотите, чтоб выглядело как в видео, добавьте к div класс состоящий из базового класса CN и "__no-results"
}
{
{commentsSectionExpanded && !isCommentsLoading && commentsLoaded && !comments.length &&
<div className={`${CN}__no-results`}>{"No comments for this post yet"}</div>}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Brackets are not needed here inside tag cause you are putting simple string as a child
can be just
<div className={${CN}__no-results}>"No comments for this post yet"</div>


// todo если секция комментариев открыта, т.е. commentsSectionExpanded = true
// но НЕ идет загрузка комментариев, т.е. isCommentsLoading = false
// и запрос уже был выполнен т.е. commentsLoaded = true
// и массив comments НЕ пустой
// показываем наши комментарии, каждый можно обвернуть в div с классом базовый класс CN + "__comment"
// рендерим с помощью comments.map
// нужно вывести имя автора comment.name (для стилизации используем класс базовый класс CN + "__comment__author")
// и текст комментария comment.body (для стилизации используем класс базовый класс CN + "__comment__text")
}
</div>
{commentsSectionExpanded && !isCommentsLoading && commentsLoaded && !!comments.length &&
<List itemRenderer={CommentListItem} options={comments}/>}
</div>
);
};
}
14 changes: 8 additions & 6 deletions src/components/UserDetails/UserDetails.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, { Component } from 'react';

import { Post } from '../Post/Post';
import { List } from '../List/List';
import { accessToken } from '../../constants';
import './UserDetails.scss';
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Styling import should be the last one among imports

import {LoadingIndicator} from "../LoadingIndicator/LoadingIndicator";

const CN = 'user-details';

Expand Down Expand Up @@ -84,15 +84,15 @@ export class UserDetails extends Component {
);
}

const { _links, first_name, last_name, dob, email, gender, address, id } = user;
const { _links, first_name, last_name, dob, email, address, id } = user;
const { avatar } = _links;

return (
<div className={CN}>
<div className={`${CN}__id`}>id:{id}</div>
<div className="user-info ">
<div className="user-info-avatar">
<img src={avatar.href} alt="photo"/>
<img src={avatar.href} alt=""/>
</div>
<div className="user-data">
<p>
Expand Down Expand Up @@ -124,9 +124,11 @@ export class UserDetails extends Component {
)
}
{
isPostsLoading && (
<div>Posts are in loading state ...</div>
)
isPostsLoading && <LoadingIndicator/>

// (
// <div>Posts are in loading state ...</div>
// )
}
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/UserDetails/UserDetails.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

.user-info {
display: flex;
align-items: start;
align-items: flex-start;
text-align: left;

&-avatar {
Expand Down
4 changes: 2 additions & 2 deletions src/constants/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// todo: добавить ваш токен
export const accessToken = '';
// добавить ваш токен
export const accessToken = 'lW8dJ26HzM99WpNSywafFacLDxtuFmHMDZ5v';
4 changes: 3 additions & 1 deletion src/containers/UserPage/UserPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { UserDetails } from '../../components/UserDetails/UserDetails';
import { UserListOption } from '../../components/UserListOption/UserListOption';
import { accessToken } from '../../constants';
import './UserPage.scss';
import {LoadingIndicator} from "../../components/LoadingIndicator/LoadingIndicator";

const CN = 'user-page';

Expand Down Expand Up @@ -65,7 +66,8 @@ export class UserPage extends Component {
error && <div>{error}</div>
}
{
isLoading && <div>Loading...</div>
isLoading && <LoadingIndicator/>
// <div>Loading...</div>
}

{
Expand Down