diff --git a/src/api/index.js b/src/api/index.js index a5f073295..11a3119fd 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -21,6 +21,7 @@ class APIService { */ async request({ url, method = 'GET', headers = {}, ...options }) { if (!url.match(/^(http|\/\/)/)) url = this.config.baseUrl + url; + const res = await fetch(url, { method, headers: { ...this.defaultHeaders, ...headers }, @@ -41,6 +42,7 @@ class APIService { delete this.defaultHeaders[name]; } } + } export default APIService; diff --git a/src/app/article/index.js b/src/app/article/index.js index 54f037b64..65edc7b20 100644 --- a/src/app/article/index.js +++ b/src/app/article/index.js @@ -1,4 +1,4 @@ -import { memo, useCallback } from 'react'; +import { memo, useCallback, useEffect } from 'react'; import { useParams } from 'react-router-dom'; import useStore from '../../hooks/use-store'; import useTranslate from '../../hooks/use-translate'; @@ -13,25 +13,37 @@ import TopHead from '../../containers/top-head'; import { useDispatch, useSelector } from 'react-redux'; import shallowequal from 'shallowequal'; import articleActions from '../../store-redux/article/actions'; +import commentsActions from '../../store-redux/comments/actions'; import HeadLayout from '../../components/head-layout'; +import CommentList from '../../components/comments-tree'; +import useSelectorStore from '../../hooks/use-selector'; +import useServices from '../../hooks/use-services'; function Article() { const store = useStore(); + const selectStore = useSelectorStore(state => ({ + user: state.session.user, + exists: state.session.exists, + })); const dispatch = useDispatch(); - // Параметры из пути /articles/:id + // Параметры из пути /articles/:id const params = useParams(); + + useInit(() => { //store.actions.article.load(params.id); dispatch(articleActions.load(params.id)); + dispatch(commentsActions.load(params.id)); }, [params.id]); const select = useSelector( state => ({ article: state.article.data, waiting: state.article.waiting, + comments: state.comments.data, }), shallowequal, ); // Нужно указать функцию для сравнения свойства объекта, так как хуком вернули объект @@ -43,6 +55,18 @@ function Article() { addToBasket: useCallback(_id => store.actions.basket.addToBasket(_id), [store]), }; + // Подписка на изменения языка + const services = useServices(); + useEffect(() => { + const unsubscribe = services.i18n.subscribe(() => { + // Повторно загружаем статью и комментарии на новом языке + dispatch(articleActions.load(params.id)); + dispatch(commentsActions.load(params.id)); + }); + + return () => unsubscribe(); // отписка при размонтировании + }, [params.id, dispatch, services.i18n]); + return ( <> @@ -55,6 +79,7 @@ function Article() { + diff --git a/src/components/comment-form/index.js b/src/components/comment-form/index.js new file mode 100644 index 000000000..5ab7422e5 --- /dev/null +++ b/src/components/comment-form/index.js @@ -0,0 +1,56 @@ +import { useState } from 'react'; +import PropTypes from 'prop-types'; +import { useDispatch, useSelector } from 'react-redux'; +import commentsActions from '../../store-redux/comments/actions'; +import Button from '../button'; +import { cn as bem } from '@bem-react/classname'; +import './style.css'; + +function CommentForm({ parentId = null, parentName = null, onCancel = () => { } }) { + const dispatch = useDispatch(); + const [text, setText] = useState(''); + const productId = useSelector(state => state.article.data?._id); + + const handleSubmit = e => { + e.preventDefault(); + if (!text.trim()) return; + + dispatch(commentsActions.add({ + text, + parent: { + _id: parentId || productId, + _type: parentId ? 'comment' : 'article', + }, + })); + + setText(''); + if (onCancel) onCancel(); // закрыть форму ответа + }; + + const cn = bem('CommentForm'); + return ( +
+
Новый {parentId ? 'ответ' : 'комментарий'}
+