Skip to content
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
2 changes: 1 addition & 1 deletion api-examples/comments.http
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Комментрии к товару

GET http://query.rest/api/v1/comments?fields=items(_id,text,dateCreate,author(profile(name)),parent(_id,_type),isDeleted),count&limit=*&search[parent]=670260bb7dd498df5525e5ed
GET http://query.rest/api/v1/comments?field=items(_id,text,dateCreate,author(profile(name)),paren(_id,_type),isDeleted),count&limit=*&search[parent]=670260bb7dd498df5525e5ed

# Остальные методы в http://query.rest/api/v1/docs/ (http://localhost:8010/api/v1/docs/)

Expand Down
6 changes: 6 additions & 0 deletions src/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class APIService {
this.config = config;
this.defaultHeaders = {
'Content-Type': 'application/json',
'X-Lang': 'ru',
};
}

Expand Down Expand Up @@ -41,6 +42,11 @@ class APIService {
delete this.defaultHeaders[name];
}
}

setLangHeader(value) {
this.setHeader('X-Lang', value);
}

}

export default APIService;
8 changes: 5 additions & 3 deletions src/app/article/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ import { useDispatch, useSelector } from 'react-redux';
import shallowequal from 'shallowequal';
import articleActions from '../../store-redux/article/actions';
import HeadLayout from '../../components/head-layout';
import Comments from "../../containers/comments";


function Article() {
const { t, lang } = useTranslate();
const store = useStore();

const dispatch = useDispatch();
Expand All @@ -26,7 +29,7 @@ function Article() {
useInit(() => {
//store.actions.article.load(params.id);
dispatch(articleActions.load(params.id));
}, [params.id]);
}, [params.id, lang]);

const select = useSelector(
state => ({
Expand All @@ -36,8 +39,6 @@ function Article() {
shallowequal,
); // Нужно указать функцию для сравнения свойства объекта, так как хуком вернули объект

const { t } = useTranslate();

const callbacks = {
// Добавление в корзину
addToBasket: useCallback(_id => store.actions.basket.addToBasket(_id), [store]),
Expand All @@ -56,6 +57,7 @@ function Article() {
<Spinner active={select.waiting}>
<ArticleCard article={select.article} onAdd={callbacks.addToBasket} t={t} />
</Spinner>
<Comments />
</PageLayout>
</>
);
Expand Down
5 changes: 2 additions & 3 deletions src/app/main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,16 @@ import HeadLayout from '../../components/head-layout';

function Main() {
const store = useStore();
const { t, lang } = useTranslate();

useInit(
async () => {
await Promise.all([store.actions.catalog.initParams(), store.actions.categories.load()]);
},
[],
[lang],
true,
);

const { t } = useTranslate();

return (
<>
<HeadLayout>
Expand Down
2 changes: 1 addition & 1 deletion src/app/profile/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ function Profile() {
<PageLayout>
<Navigation />
<Spinner active={select.waiting}>
<ProfileCard data={select.profile} />
<ProfileCard t={t} data={select.profile} />
</Spinner>
</PageLayout>
</>
Expand Down
8 changes: 4 additions & 4 deletions src/components/article-card/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@ function ArticleCard(props) {
<div className={cn('description')}>{article.description}</div>
<div className={cn('prop-wrapper')}>
<div className={cn('prop')}>
<div className={cn('label')}>Страна производитель:</div>
<div className={cn('label')}>{t('article.madeIn')}:</div>
<div className={cn('value')}>
{article.madeIn?.title} ({article.madeIn?.code})
</div>
</div>
<div className={cn('prop')}>
<div className={cn('label')}>Категория:</div>
<div className={cn('label')}>{t('article.category')}:</div>
<div className={cn('value')}>{article.category?.title}</div>
</div>
<div className={cn('prop')}>
<div className={cn('label')}>Год выпуска:</div>
<div className={cn('label')}>{t('article.edition')}:</div>
<div className={cn('value')}>{article.edition}</div>
</div>
</div>
<div className={cn('prop', { size: 'big' })}>
<div className={cn('label')}>Цена:</div>
<div className={cn('label')}>{t('article.price')}:</div>
<div className={cn('value')}>{numberFormat(article.price)} ₽</div>
</div>
<Button style="primary" onClick={() => onAdd(article._id)} title={t('article.add')} />
Expand Down
2 changes: 1 addition & 1 deletion src/components/button/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function Button({ onClick = () => {}, title, style, type = 'button' }) {
Button.propTypes = {
onClick: PropTypes.func,
title: PropTypes.string,
style: PropTypes.oneOf(['text', 'primary', 'delete', 'outline']),
style: PropTypes.oneOf(['text', 'primary', 'delete', 'outline', 'text-com']),
type: PropTypes.oneOf(['button', 'submit']),
};

Expand Down
14 changes: 13 additions & 1 deletion src/components/button/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,20 @@
.Button_style_text {
padding: 0;
border: none;
color: var(--primary);

&:hover {
color: var(--primary);
color: var(--main-text);
}
}

.Button_style_text-com {
padding: 0;
border: none;
font-size: 12px;
color: var(--primary);

&:hover {
color: var(--main-text);
}
}
128 changes: 128 additions & 0 deletions src/components/comment-item/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import React, {useCallback, useEffect, useRef} from 'react';
import './style.css';
import formatDate from '../../utils/format-date';
import Button from '../button';
import Textarea from '../textarea';

const CommentItem = ({
comment,
activeReplyId = null,
setActiveReplyId = _id => {},
isAuth = false,
postCommentText = '',
setPostCommentText = () => {},
onPost = () => {},
sessionUserId = null,
goToLogin = () => {},
t = z => {},
lang = 'ru',
level = 0,
}) => {

const replyRef = useRef(null);

const callbacks = {
onReply: useCallback(() => {
setActiveReplyId(comment._id);
setPostCommentText('');
}, []),
onActiveReplyReset: useCallback(() => {
setActiveReplyId(null);
setPostCommentText('');
}, []),
};

useEffect(() => {
if (activeReplyId === comment._id && replyRef.current) {
replyRef.current.scrollIntoView({
behavior: 'smooth',
block: 'center',
});
}
}, [activeReplyId, comment._id]);

return (
<>
<div className="com-item">
<div className="com-item-head">
<div
className={
'com-item-head-name' +
(sessionUserId === comment.author._id ? ' com-item-head-name_user' : '')
}
>
{comment?.author?.profile?.name}
</div>
<div className="com-item-head-date">{formatDate(comment?.dateCreate, lang)}</div>
</div>

<div className="com-item-body">{comment?.text}</div>

<Button style="text-com" onClick={callbacks.onReply} title={t('comments.reply')} />
</div>

<div className={level <= 10 ? 'com-item-children' : 'com-item-children_no-padding'}>
{comment.children.length > 0 && (
<>
{comment.children.map(child => (
<CommentItem
key={child._id}
comment={child}
activeReplyId={activeReplyId}
setActiveReplyId={setActiveReplyId}
isAuth={isAuth}
postCommentText={postCommentText}
setPostCommentText={setPostCommentText}
onPost={onPost}
sessionUserId={sessionUserId}
goToLogin={goToLogin}
t={t}
lang={lang}
level={level + 1}
/>
))}
</>
)}
{activeReplyId === comment._id && (
<div ref={replyRef}>
{isAuth ? (
<Textarea
onCancel={callbacks.onActiveReplyReset}
parentType="comment"
title={t('comments.new-reply-title')}
postCommentText={postCommentText}
setPostCommentText={setPostCommentText}
onPost={onPost}
t={t}
/>
) : (
<div className={'com-item-unAuth'}>
<Button style={'text'} title={t('comments.unAuth-btn')} onClick={goToLogin} />
{t('comments.unAuth-text')}
</div>
)}
</div>
)}
{/*{activeReplyId === comment._id && isAuth && (*/}
{/* <Textarea*/}
{/* onCancel={callbacks.onActiveReplyReset}*/}
{/* parentType="comment"*/}
{/* title={t('comments.new-reply-title')}*/}
{/* postCommentText={postCommentText}*/}
{/* setPostCommentText={setPostCommentText}*/}
{/* onPost={onPost}*/}
{/* t={t}*/}
{/* />*/}
{/*)}*/}
{/*{activeReplyId === comment._id && !isAuth && (*/}
{/* <div className={'com-item-unAuth'}>*/}
{/* <Button style={'text'} title={t('comments.unAuth-btn')} onClick={goToLogin} />*/}
{/* {t('comments.unAuth-text')}*/}
{/* </div>*/}
{/*)}*/}
</div>
</>
);
};

export default CommentItem;
48 changes: 48 additions & 0 deletions src/components/comment-item/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
.com-item {
color: #000000;
display: flex;
gap: 6px;
flex-direction: column;
margin-bottom: 16px;
}

.com-item-head {
font-size: 12px;
display: flex;
gap: 12px;
line-height: 18px;
/*padding-bottom: 6px;*/
}

.com-item-head-name {
font-weight: bold;
}

.com-item-head-date {
color: #666666;
}

.com-item-body {
font-size: 14px;
line-height: 20px;
overflow-wrap: break-word;
white-space: normal;
}

.com-item-children {
padding-left: 40px;
}

.com-item-children_no-padding {

}

.com-item-unAuth {
display: flex;
flex-direction: row;
margin-bottom: 16px;
}

.com-item-head-name_user {
color: var(--user-comment);
}
63 changes: 63 additions & 0 deletions src/components/comment-list/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React, {memo} from 'react';
import CommentItem from '../comment-item';
import Textarea from '../textarea';
import './style.css';
import Button from "../button";

const CommentList = ({
onPost = () => {},
isAuth = false,
commentTree = [],
commentCount = 0,
postCommentText = '',
setPostCommentText = () => {},
activeReplyId = null,
setActiveReplyId = () => {},
sessionUserId = null,
goToLogin = () => {},
t = (z) => {},
lang = 'ru',
}) => {

return (
<>
<div className="comList-title">{t('comments.title')} ({commentCount})</div>
<div>
{commentTree.map(comment => (
<CommentItem
isAuth={isAuth}
key={comment._id}
comment={comment}
activeReplyId={activeReplyId}
setActiveReplyId={setActiveReplyId}
postCommentText={postCommentText}
setPostCommentText={setPostCommentText}
onPost={onPost}
sessionUserId={sessionUserId}
goToLogin={goToLogin}
t={t}
lang={lang}
/>
))}
</div>
{!activeReplyId && isAuth &&
<Textarea
onPost={onPost}
title={t('comments.new-comment-title')}
parentType="article"
postCommentText={postCommentText}
setPostCommentText={setPostCommentText}
t={t}
/>
}
{!activeReplyId && !isAuth &&
<div className={'com-item-unAuth'}>
<Button style={'text'} title={t('comments.unAuth-btn')} onClick={goToLogin} />
{t('comments.unAuth-text')}
</div>
}
</>
);
};

export default memo(CommentList);
Loading