Skip to content

Commit

Permalink
lecture-5
Browse files Browse the repository at this point in the history
  • Loading branch information
danilandreevic committed Oct 12, 2024
1 parent 9d3c4c0 commit 8c3412c
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 36 deletions.
44 changes: 26 additions & 18 deletions src/components/article-comment/index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import React from 'react';
import React, { useRef, useEffect } from 'react';
import CommentForm from '../comment-form/index';
import { cn as bem } from '@bem-react/classname';
import './style.css';
import { Link } from 'react-router-dom';

const ArticleComments = ({ comments, replyTo, setReplyTo, handleAddComment, exists, link }) => {
const ArticleComments = ({ comments, replyTo, setReplyTo, handleAddComment, exists, link,user }) => {
const cn = bem('ArticleComments');

const maxDepth = 3;
const replyFormRef = useRef(null);
useEffect(() => {
if (replyFormRef.current) {
replyFormRef.current.scrollIntoView({ behavior: 'smooth' });
}
}, [replyTo]);
const renderComment = (comment) => (
<li key={comment._id} className={cn('item', { child: comment.parent })}>
<li key={comment._id} className={cn('item', { child: comment.parent && comment.depth <= maxDepth })}>
<div className={cn('content')}>
<p className={cn('author')}>
<span>{comment.author.profile.name}</span>
<span className={cn('date')}>
<span className={comment.author?.profile?.name === user.profile?.name ? cn('author-name') : ''}>{comment.author?.profile?.name}</span> <span className={cn('date')}>
{new Date(comment.dateCreate).toLocaleDateString('ru-RU', {
day: 'numeric',
month: 'long',
Expand All @@ -25,26 +30,29 @@ const ArticleComments = ({ comments, replyTo, setReplyTo, handleAddComment, exis
})}
</span>
</p>
<p>{comment.text}</p>
<p className={cn('text')}>{comment.text}</p>
<button
className={cn('reply-button')}
onClick={() => setReplyTo(comment._id)}
>
Ответить
</button>
{replyTo === comment._id && (
exists ? (
<CommentForm onSubmit={(text) => handleAddComment(text, comment._id)}/>
) : (
<div className={cn('login')}>
<Link className={cn('link-login')} to={link}>Войдите</Link>, чтобы иметь возможность комментировать.
<button className={cn('button-cancel')} onClick={() => setReplyTo(null)}>Отмена</button>
</div>
)
)}
</div>
{comment.children && (
<ul className={cn('list')}>{comment.children.map(renderComment)}</ul>
<ul className={cn('list')}>
{comment.children.map(renderComment)}
{replyTo === comment._id && (
exists ? (
<div ref={replyFormRef}>
<CommentForm onSubmit={(text) => handleAddComment(text, comment._id)} onCancel={() => setReplyTo(null)} /> </div>
) : (
<div className={cn('login')} ref={replyFormRef}>
<Link className={cn('link-login')} to={link}>Войдите</Link>, чтобы иметь возможность комментировать.
<button className={cn('button-cancel')} onClick={() => setReplyTo(null)}>Отмена</button>
</div>
)
)}
</ul>
)}
</li>
);
Expand Down
54 changes: 54 additions & 0 deletions src/containers/article-comments/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { memo, useCallback, useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useParams } from 'react-router-dom';
import shallowequal from 'shallowequal';
import { fetchComments, addComment } from '../../store-redux/comments/actions';
import ArticleComments from '../../components/article-comment';
import listToTree from '../../utils/list-to-tree';
import useStoreSelector from '../../hooks/use-selector';

function ArticleCommentsContainer() {
const dispatch = useDispatch();
const params = useParams();
const [replyTo, setReplyTo] = useState(null);

useEffect(() => {
dispatch(fetchComments(params.id));
}, [params.id, dispatch]);

const select = useSelector(
state => ({
comments: state.comments.comments,
}),
shallowequal,
);

const storeSelect = useStoreSelector(
state => ({
exists: state.session.exists,
token: state.session.token,
user: state.session.user,
}),
);

const handleAddComment = useCallback((text, parentId) => {
const parent = parentId ? { _id: parentId, _type: 'comment' } : { _id: params.id, _type: 'article' };
dispatch(addComment({ text, parent, article: params.id, token: storeSelect.token }));
setReplyTo(null);
}, [dispatch, params.id, storeSelect.token]);

const organizedComments = listToTree(select.comments);
return (
<ArticleComments
comments={organizedComments}
replyTo={replyTo}
setReplyTo={setReplyTo}
handleAddComment={handleAddComment}
exists={storeSelect.exists}
link="/login"
user={storeSelect.user}
/>
);
}

export default memo(ArticleCommentsContainer);
39 changes: 21 additions & 18 deletions src/utils/list-to-tree/index.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,37 @@
/**
* Преобразование списка в иерархию
* @param list {Array} Список объектов с отношением на родителя
* @param [key] {String} Свойство с первичным ключом
* @returns {Array} Корневые узлы
*/
export default function listToTree(list, key = '_id') {
export default function listToTree(list, key = '_id', maxDepth = 6) {
let trees = {};
let roots = {};
let depths = {};

for (const item of list) {
// Добавление элемента в индекс узлов и создание свойства children
if (!depths[item[key]]) {
depths[item[key]] = 0;
}


if (!trees[item[key]]) {
trees[item[key]] = item;
trees[item[key]].children = [];
// Ещё никто не ссылался, поэтому пока считаем корнем
roots[item[key]] = trees[item[key]];
} else {
trees[item[key]] = Object.assign(trees[item[key]], item);
}

// Если элемент имеет родителя, то добавляем его в подчиненные родителя
if (item.parent?.[key]) {
// Если родителя ещё нет в индексе, то индекс создаётся, ведь _id родителя известен
if (!trees[item.parent[key]]) {
trees[item.parent[key]] = { children: [] };
roots[item.parent[key]] = trees[item.parent[key]];
const parentExists = list.some(parentItem => parentItem[key] === item.parent[key]);

if (parentExists) {
if (!trees[item.parent[key]]) {
trees[item.parent[key]] = { children: [] };
}
if (depths[item.parent[key]] < maxDepth - 1) {
trees[item.parent[key]].children.push(trees[item[key]]);
depths[item[key]] = depths[item.parent[key]] + 1;
if (roots[item[key]]) {
delete roots[item[key]];
}
}
}
// Добавления в подчиненные родителя
trees[item.parent[key]].children.push(trees[item[key]]);
// Так как элемент добавлен к родителю, то он уже не является корневым
if (roots[item[key]]) delete roots[item[key]];
}
}
return Object.values(roots);
Expand Down

0 comments on commit 8c3412c

Please sign in to comment.