diff --git a/src/components/button/index.js b/src/components/button/index.js
index 7d1d3d05c..cfc6fb214 100644
--- a/src/components/button/index.js
+++ b/src/components/button/index.js
@@ -8,7 +8,7 @@ function Button({ onClick = () => {}, title, style, type = 'button' }) {
return (
-
+
);
}
diff --git a/src/components/comment-form/index.js b/src/components/comment-form/index.js
new file mode 100644
index 000000000..1340f57c9
--- /dev/null
+++ b/src/components/comment-form/index.js
@@ -0,0 +1,105 @@
+import React, { useState, useEffect, useRef } from 'react';
+import PropTypes from 'prop-types';
+import { cn as bem } from '@bem-react/classname';
+import useTranslate from '../../hooks/use-translate';
+import { useNavigate } from 'react-router-dom';
+import './style.css';
+import Button from '../button';
+
+function FormComment({
+ mode,
+ title,
+ id = '',
+ sendComment,
+ type,
+ exists,
+ setFormCommentIsActive = () => {},
+ currentCommentId,
+}) {
+ const cn = bem('FormComment');
+ const { t } = useTranslate();
+ const navigate = useNavigate();
+ const [text, setText] = useState('');
+ const formRef = useRef(null);
+
+ useEffect(() => {
+ if (formRef.current && mode === 'answer') {
+ formRef.current.scrollIntoView({ behavior: 'smooth' });
+ }
+ }, []);
+
+ function handleCansel(e) {
+ e.preventDefault();
+ setFormCommentIsActive();
+ }
+ function signIn() {
+ navigate('/login', { state: { back: location.pathname } });
+ }
+
+ function handleAnswer(e) {
+ e.preventDefault();
+ if (!text.replace(/\s+/g, '')) {
+ return;
+ }
+ if (mode === 'answer') {
+ sendComment({ text, parent: { _id: currentCommentId, _type: type } });
+ setText('');
+ } else {
+ sendComment({ text, parent: { _id: id, _type: type } });
+ setText('');
+ }
+ }
+
+ return (
+ <>
+ {exists ? (
+
+ ) : (
+ <>
+ {mode === 'answer' ? (
+
+ {' '}
+
Войдите, чтобы иметь возможность ответить.
+
+ ) : (
+
+ {' '}
+
Войдите, чтобы иметь возможность комментировать
+
+ )}
+ >
+ )}
+ >
+ );
+}
+
+FormComment.propTypes = {
+ mode: PropTypes.string,
+ title: PropTypes.string,
+ id: PropTypes.string,
+ setIdActiveAnswer: PropTypes.func,
+ sendComment: PropTypes.func,
+ type: PropTypes.string,
+};
+
+export default React.memo(FormComment);
diff --git a/src/components/comment-form/style.css b/src/components/comment-form/style.css
new file mode 100644
index 000000000..0fb5e226e
--- /dev/null
+++ b/src/components/comment-form/style.css
@@ -0,0 +1,37 @@
+.FormComment {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ margin-top: 30px;
+}
+
+.FormComment-title {
+ font-size: 16px;
+ font-weight: bold;
+ margin: 0;
+}
+
+.FormComment-textarea {
+ margin-top: 8px;
+ width: 100%;
+ font-size: 14px;
+ resize: none;
+ border-color: rgba(211, 211, 211, 1);
+ border-radius: 5px;
+}
+
+.FormComment-actions {
+ margin-top: 8px;
+ display: flex;
+ justify-content: flex-start;
+ gap: 10px;
+}
+
+.FormComment-login {
+ margin-top: 30px;
+}
+
+.FormComment-login > a {
+ color: var(--primary);
+ cursor: pointer;
+}
diff --git a/src/components/comment-item/index.js b/src/components/comment-item/index.js
new file mode 100644
index 000000000..ab2349365
--- /dev/null
+++ b/src/components/comment-item/index.js
@@ -0,0 +1,72 @@
+import React, { useMemo } from 'react';
+import PropTypes from 'prop-types';
+import { cn as bem } from '@bem-react/classname';
+import FormComment from '../comment-form';
+import useTranslate from '../../hooks/use-translate';
+import './style.css';
+
+function ItemComment(props) {
+ const cn = bem('ItemComment');
+ const { t } = useTranslate();
+
+ const computedLevel = useMemo(() => {
+ if (props.level > 10) return 10;
+ return props.level;
+ }, [props.level]);
+
+ const correctDatetime = useMemo(() => {
+ const date = new Date(props.datetime);
+ const options = {
+ day: '2-digit',
+ month: 'long',
+ year: 'numeric',
+ hour: '2-digit',
+ minute: '2-digit',
+ };
+ return date.toLocaleDateString('ru-RU', options).replace(' г.', '');
+ }, [props.datetime]);
+
+ function handleAnswer() {
+ props.setFormAnswerIsActive(props.id);
+ props.addForm(props.id, props.level, props.comments);
+ }
+
+ return (
+
+
+
{props.name}
+
{correctDatetime}
+
+
{props.text}
+
+ {props.answer}
+
+ {props.formAnswerIsActive && props.index1 === props.index2 && (
+
+ )}
+
+ );
+}
+
+ItemComment.propTypes = {
+ name: PropTypes.string,
+ text: PropTypes.string,
+ datetime: PropTypes.string,
+ level: PropTypes.number,
+ answer: PropTypes.string,
+ exists: PropTypes.bool,
+ setIdActiveAnswer: PropTypes.func,
+ idActiveAnswer: PropTypes.string,
+ sendComment: PropTypes.func,
+};
+
+export default React.memo(ItemComment);
diff --git a/src/components/comment-item/style.css b/src/components/comment-item/style.css
new file mode 100644
index 000000000..097ed5d07
--- /dev/null
+++ b/src/components/comment-item/style.css
@@ -0,0 +1,80 @@
+.ItemComment {
+ display: flex;
+ flex-direction: column;
+ align-self: flex-start;
+ gap: 7px;
+ width: 100%;
+}
+.ItemComment-level-1 {
+ margin-left: 0;
+}
+.ItemComment-level-2 {
+ margin-left: 40px;
+ width: calc(100% - 40px);
+}
+.ItemComment-level-3 {
+ margin-left: 80px;
+ width: calc(100% - 80px);
+}
+.ItemComment-level-4 {
+ margin-left: 120px;
+ width: calc(100% - 120px);
+}
+.ItemComment-level-5 {
+ margin-left: 160px;
+ width: calc(100% - 160px);
+}
+.ItemComment-level-6 {
+ margin-left: 200px;
+ width: calc(100% - 200px);
+}
+.ItemComment-level-7 {
+ margin-left: 240px;
+ width: calc(100% - 240px);
+}
+.ItemComment-level-8 {
+ margin-left: 280px;
+ width: calc(100% - 280px);
+}
+.ItemComment-level-9 {
+ margin-left: 320px;
+ width: calc(100% - 320px);
+}
+.ItemComment-level-10 {
+ margin-left: 360px;
+ width: calc(100% - 360px);
+}
+
+.ItemComment-header {
+ display: flex;
+ justify-content: flex-start;
+ gap: 10px;
+}
+
+.ItemComment-user {
+ font-weight: bold;
+ font-size: 12px;
+}
+
+.ItemComment-datetime {
+ font-size: 12px;
+ color: #666666;
+}
+
+.ItemComment-text {
+ font-size: 14px;
+ word-wrap: break-word;
+}
+
+.ItemComment-answer {
+ color: var(--primary);
+ font-size: 12px;
+ font-weight: bold;
+ font-family: 'Montserrat Alternates', sans-serif;
+ cursor: pointer;
+}
+
+.ItemComment-login {
+ margin-top: 30px;
+}
+
diff --git a/src/components/comment-layout/index.js b/src/components/comment-layout/index.js
new file mode 100644
index 000000000..476f29a19
--- /dev/null
+++ b/src/components/comment-layout/index.js
@@ -0,0 +1,15 @@
+import React from 'react';
+import './style.css';
+
+function CommentLayout({ children, count, title }) {
+ return (
+
+
+ {title} ({count}){' '}
+
+ {children}
+
+ );
+}
+
+export default CommentLayout;
diff --git a/src/components/comment-layout/style.css b/src/components/comment-layout/style.css
new file mode 100644
index 000000000..07d04fdf2
--- /dev/null
+++ b/src/components/comment-layout/style.css
@@ -0,0 +1,9 @@
+.CommentLayout {
+ margin-top: 40px;
+}
+
+.CommentLayout-header {
+ font-family: 'Montserrat Alternates', sans-serif;
+ font-size: 24px;
+ font-weight: 24px;
+}
diff --git a/src/components/comment-list/index.js b/src/components/comment-list/index.js
new file mode 100644
index 000000000..e775f8854
--- /dev/null
+++ b/src/components/comment-list/index.js
@@ -0,0 +1,8 @@
+import React from 'react';
+import './style.css';
+
+function CommentsList({ children }) {
+ return {children}
;
+}
+
+export default CommentsList;
diff --git a/src/components/comment-list/style.css b/src/components/comment-list/style.css
new file mode 100644
index 000000000..974b31471
--- /dev/null
+++ b/src/components/comment-list/style.css
@@ -0,0 +1,6 @@
+.CommentsList {
+ display: flex;
+ flex-direction: column;
+ gap: 25px;
+ margin-top: 30px;
+}
diff --git a/src/containers/comment/index.js b/src/containers/comment/index.js
new file mode 100644
index 000000000..a891f0883
--- /dev/null
+++ b/src/containers/comment/index.js
@@ -0,0 +1,130 @@
+import React, { useMemo } from 'react';
+import { useCallback } from 'react';
+import { useParams } from 'react-router-dom';
+import ItemComment from '../../components/comment-item';
+import useTranslate from '../../hooks/use-translate';
+import useSelector from '../../hooks/use-selector';
+import { useSelector as useSelectorRedux } from 'react-redux';
+import { useStore as useStoreRedux } from 'react-redux';
+import { useDispatch } from 'react-redux';
+import shallowequal from 'shallowequal';
+import commentsActions from '../../store-redux/comment/actions';
+import FormComment from '../../components/comment-form';
+import treeToList from '../../utils/tree-to-list';
+import listToTree from '../../utils/list-to-tree';
+import CommentLayout from '../../components/comment-layout';
+import CommentsList from '../../components/comment-list';
+
+function Comments() {
+ const { t } = useTranslate();
+ const store = useStoreRedux();
+ const dispatch = useDispatch();
+ const params = useParams();
+
+ const select = useSelector(state => ({
+ exists: state.session.exists,
+ name: state.session.user.profile?.name,
+ }));
+
+ const selectRedux = useSelectorRedux(
+ state => ({
+ count: state.comment.count,
+ comments: state.comment.data,
+ index: state.comment.index,
+ formCommentIsActive: state.comment.formCommentIsActive,
+ formAnswerIsActive: state.comment.formAnswerIsActive,
+ currentCommentId: state.comment.currentCommentId,
+ }),
+ shallowequal,
+ );
+
+ const callbacks = {
+ // Установка идентификатора для ответа на комментарий
+ setIdActiveAnswer: useCallback(
+ id => {
+ dispatch(commentsActions.setIdActiveAnswer(id));
+ },
+ [store],
+ ),
+ sendComment: useCallback(
+ (comment, name = select.name) => {
+ dispatch(commentsActions.send({ ...comment }, name));
+ },
+ [store],
+ ),
+ setFormAnswerIsActive: useCallback(
+ id => {
+ dispatch(commentsActions.setFormAnswerIsActive(id));
+ },
+ [store],
+ ),
+ setFormCommentIsActive: useCallback(() => {
+ dispatch(commentsActions.setFormCommentIsActive());
+ }),
+ addForm: useCallback(
+ (id, level, comments) => {
+ dispatch(commentsActions.addForm(id, level, comments));
+ },
+ [store],
+ ),
+ };
+
+ const options = {
+ comments: useMemo(
+ () => [
+ ...treeToList(listToTree(selectRedux.comments), (item, level) => ({
+ name: item.author?.profile?.name,
+ datetime: item.dateCreate,
+ value: item._id,
+ text: item.text,
+ level: level,
+ mode: 'comment',
+ })),
+ ],
+ [selectRedux.comments],
+ ),
+ };
+
+ return (
+
+
+ {options.comments.map(
+ (item, index) =>
+ item.value && (
+
+ ),
+ )}
+
+ {selectRedux.formCommentIsActive && (
+
+ )}
+
+ );
+}
+
+export default React.memo(Comments);
diff --git a/src/hooks/use-translate.js b/src/hooks/use-translate.js
index bdcbf1071..62ab34dfb 100644
--- a/src/hooks/use-translate.js
+++ b/src/hooks/use-translate.js
@@ -1,9 +1,26 @@
-import { useCallback, useContext } from 'react';
-import { I18nContext } from '../i18n/context';
+import { useState, useEffect } from 'react';
+import useServices from '../hooks/use-services';
/**
* Хук возвращает функцию для локализации текстов, код языка и функцию его смены
*/
export default function useTranslate() {
- return useContext(I18nContext);
+ const { i18n } = useServices();
+ const [lang, setLang] = useState(i18n.getLang());
+
+ // Подписываемся и отписываемся при размонтировании
+ useEffect(() => {
+ const unsubscribe = i18n.subscribe(setLang);
+
+ return () => unsubscribe();
+ }, [i18n]);
+
+ return {
+ // Код локали
+ lang,
+ // Функция для смены локали
+ setLang: i18n.setLang.bind(i18n),
+ // Функция для локализации текстов с замыканием на код языка
+ t: i18n.translate.bind(i18n),
+ };
}
diff --git a/src/i18n/context.js b/src/i18n/context.js
deleted file mode 100644
index 3733d9bac..000000000
--- a/src/i18n/context.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import { createContext, useMemo, useState } from 'react';
-import translate from './translate';
-
-/**
- * @type {React.Context<{}>}
- */
-export const I18nContext = createContext({});
-
-/**
- * Обертка над провайдером контекста, чтобы управлять изменениями в контексте
- * @param children
- * @return {JSX.Element}
- */
-export function I18nProvider({ children }) {
- const [lang, setLang] = useState('ru');
-
- const i18n = useMemo(
- () => ({
- // Код локали
- lang,
- // Функция для смены локали
- setLang,
- // Функция для локализации текстов с замыканием на код языка
- t: (text, number) => translate(lang, text, number),
- }),
- [lang],
- );
-
- return {children};
-}
diff --git a/src/i18n/index.js b/src/i18n/index.js
new file mode 100644
index 000000000..6d0d205af
--- /dev/null
+++ b/src/i18n/index.js
@@ -0,0 +1,48 @@
+import * as translations from './translations';
+
+class i18nService {
+ constructor() {
+ this.lang = 'ru';
+ this.listeners = new Set();
+ }
+
+ // Меняем язык
+ setLang(lang) {
+ if (this.lang !== lang) {
+ this.lang = lang;
+ this.sentNotify(lang);
+ }
+ }
+
+ // Получаем язык
+ getLang() {
+ return this.lang;
+ }
+
+ // Переносим нашу функцию translate из translate.js
+ translate(text, lang = this.lang, plural) {
+ let result = translations[lang] && text in translations[lang] ? translations[lang][text] : text;
+
+ if (typeof plural !== 'undefined') {
+ const key = new Intl.PluralRules(lang).select(plural);
+ if (key in result) {
+ result = result[key];
+ }
+ }
+
+ return result;
+ }
+
+ // Добавляем в слушатели
+ subscribe(callback) {
+ this.listeners.add(callback);
+ return () => this.listeners.delete(callback);
+ }
+
+ // Передаем слушателям новый язык при смене
+ sentNotify(lang) {
+ this.listeners.forEach(cb => cb(lang));
+ }
+}
+
+export default i18nService;
diff --git a/src/i18n/translate.js b/src/i18n/translate.js
deleted file mode 100644
index c4c60db93..000000000
--- a/src/i18n/translate.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import * as translations from './translations';
-
-/**
- * Перевод фразу по словарю
- * @param lang {String} Код языка
- * @param text {String} Текст для перевода
- * @param [plural] {Number} Число для плюрализации
- * @returns {String} Переведенный текст
- */
-export default function translate(lang, text, plural) {
- let result = translations[lang] && text in translations[lang] ? translations[lang][text] : text;
-
- if (typeof plural !== 'undefined') {
- const key = new Intl.PluralRules(lang).select(plural);
- if (key in result) {
- result = result[key];
- }
- }
-
- return result;
-}
diff --git a/src/i18n/translations/en.json b/src/i18n/translations/en.json
index 0ebbcf8f2..d1424be7e 100644
--- a/src/i18n/translations/en.json
+++ b/src/i18n/translations/en.json
@@ -22,5 +22,11 @@
"auth.login-placeholder": "Enter login",
"auth.password-placeholder": "Enter password",
"session.signIn": "Sign In",
- "session.signOut": "Sign Out"
+ "session.signOut": "Sign Out",
+ "comment.title": "Comments",
+ "comment.btn.answer": "Answer",
+ "comment.newComment": "New Comment",
+ "comment.newAnswer": "New Answer",
+ "comment.btn.send": "Send",
+ "comment.btn.cancel": "Cancel"
}
diff --git a/src/i18n/translations/ru.json b/src/i18n/translations/ru.json
index a18fb845e..2df8d5603 100644
--- a/src/i18n/translations/ru.json
+++ b/src/i18n/translations/ru.json
@@ -24,5 +24,11 @@
"auth.login-placeholder": "Введите логин",
"auth.password-placeholder": "Введите пароль",
"session.signIn": "Вход",
- "session.signOut": "Выход"
+ "session.signOut": "Выход",
+ "comment.title": "Комментарии",
+ "comment.btn.answer": "Ответить",
+ "comment.newComment": "Новый комментарий",
+ "comment.newAnswer": "Новый ответ",
+ "comment.btn.send": "Отправить",
+ "comment.btn.cancel": "Отмена"
}
diff --git a/src/index.js b/src/index.js
index f49db385a..9404d09eb 100644
--- a/src/index.js
+++ b/src/index.js
@@ -2,7 +2,6 @@ import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import { ServicesContext } from './context';
-import { I18nProvider } from './i18n/context';
import App from './app';
import Services from './services';
import config from './config';
@@ -16,11 +15,9 @@ const root = createRoot(document.getElementById('root'));
root.render(
-
-
-
-
-
+
+
+
,
);
diff --git a/src/services.js b/src/services.js
index a32b14d57..76ed26e8e 100644
--- a/src/services.js
+++ b/src/services.js
@@ -1,5 +1,6 @@
import APIService from './api';
import Store from './store';
+import i18nService from './i18n';
import createStoreRedux from './store-redux';
class Services {
@@ -38,6 +39,13 @@ class Services {
}
return this._redux;
}
+
+ get i18n() {
+ if (!this._i18n) {
+ this._i18n = new i18nService(this, this.config.i18n);
+ }
+ return this._i18n;
+ }
}
export default Services;
diff --git a/src/store-redux/comment/actions.js b/src/store-redux/comment/actions.js
new file mode 100644
index 000000000..ca3bdce52
--- /dev/null
+++ b/src/store-redux/comment/actions.js
@@ -0,0 +1,81 @@
+export default {
+
+ load: id => {
+ return async (dispatch, getState, services) => {
+ dispatch({ type: 'comments/load-start' });
+
+ try {
+ const res = await services.api.request({
+ url: `/api/v1/comments?fields=items(_id,text,dateCreate,author(profile(name)),parent(_id,_type),isDeleted),count&limit=*&search[parent]=${id}`,
+ });
+
+ dispatch({ type: 'comments/load-success', payload: { data: res.data.result } });
+ }
+ catch (e) {
+ dispatch({ type: 'comments/load-error' });
+ }
+ };
+ },
+
+ send: (comment, name) => {
+ return async (dispatch, getState, services) => {
+ dispatch({ type: 'comments/send-start' });
+
+ try {
+ const res = await services.api.request({
+ url: '/api/v1/comments',
+ method: 'POST',
+ body: JSON.stringify(comment),
+ })
+ const temp = {
+ ...res.data.result,
+ author: {profile: {name: name}},
+ }
+ console.log(temp)
+ dispatch({ type: 'comments/send-success', payload: { temp } });
+ dispatch({ type: 'comments/setFormCommentIsActive', payload: { formCommentIsActive: true, formAnswerIsActive: false } });
+ }
+ catch (e) {
+ dispatch({ type: 'comments/send-error' });
+ }
+ }
+ },
+
+ addForm: (id, level, comments) => {
+ return (dispatch) => {
+ const parentIndex = comments.findIndex(item => item.value === id);
+ let lastChildIndex
+ let res
+ for (let i = parentIndex + 1; i < comments.length; i++) {
+ if (comments[i].level <= level) {
+ break
+ }
+ if (comments[i].level === level + 1) {
+ lastChildIndex = i
+ }
+ }
+
+ if (lastChildIndex) {
+ res = lastChildIndex
+ }
+ else {
+ res = parentIndex
+ }
+ dispatch({ type: 'comments/addForm', payload: { res: res } });
+ }
+ },
+
+ setFormAnswerIsActive: (id) => {
+ return {
+ type: 'comments/setFormAnswerIsActive',
+ payload: {formAnswerIsActive: true, formCommentIsActive: false, id: id},
+ }
+ },
+
+ setFormCommentIsActive: () => {
+ return {
+ type: 'comments/setFormCommentIsActive',
+ payload: {formAnswerIsActive: false, formCommentIsActive: true},
+ }
+ },
+};
diff --git a/src/store-redux/comment/reducer.js b/src/store-redux/comment/reducer.js
new file mode 100644
index 000000000..684f4c6d5
--- /dev/null
+++ b/src/store-redux/comment/reducer.js
@@ -0,0 +1,64 @@
+export const initialState = {
+ data: [],
+ count: 0,
+ waiting: false,
+ formCommentIsActive: true,
+ formAnswerIsActive: false,
+ index: null,
+ currentCommentId: null,
+};
+
+function reducer(state = initialState, action) {
+ switch (action.type) {
+ case 'comments/load-start':
+ return { ...state, data: [], count: 0, waiting: true };
+
+ case 'comments/load-success':
+ return {
+ ...state,
+ data: action.payload.data.items,
+ count: action.payload.data.count,
+ waiting: false,
+ };
+
+ case 'comments/load-error':
+ return { ...state, data: [], count: 0, waiting: false };
+
+ case 'comments/send-start':
+ return { ...state, waiting: true };
+
+ case 'comments/send-success':
+ return {
+ ...state,
+ data: [...state.data, action.payload.temp],
+ idActiveAnswer: null,
+ waiting: false,
+ };
+
+ case 'comments/send-error':
+ return { ...state, waiting: false };
+
+ case 'comments/setFormAnswerIsActive':
+ return {
+ ...state,
+ formAnswerIsActive: action.payload.formAnswerIsActive,
+ formCommentIsActive: action.payload.formCommentIsActive,
+ currentCommentId: action.payload.id,
+ };
+
+ case 'comments/setFormCommentIsActive':
+ return {
+ ...state,
+ formCommentIsActive: action.payload.formCommentIsActive,
+ formAnswerIsActive: action.payload.formAnswerIsActive,
+ };
+
+ case 'comments/addForm':
+ return { ...state, index: action.payload.res };
+
+ default:
+ return state;
+ }
+}
+
+export default reducer;
diff --git a/src/store-redux/exports.js b/src/store-redux/exports.js
index 1a0a3d742..bbea750c9 100644
--- a/src/store-redux/exports.js
+++ b/src/store-redux/exports.js
@@ -1,2 +1,3 @@
export { default as article } from './article/reducer';
export { default as modals } from './modals/reducer';
+export { default as comment } from './comment/reducer';
From 4bfad0ad6c0e97dfd56a3ce0154763bc419e5fa9 Mon Sep 17 00:00:00 2001
From: PonomarevAlexx <136852344+PonomarevAlexx@users.noreply.github.com>
Date: Mon, 21 Apr 2025 15:17:05 +0300
Subject: [PATCH 3/4] fixed
---
src/components/comment-form/index.js | 3 +--
src/components/comment-item/index.js | 13 +++++++++----
src/components/comment-item/style.css | 4 ++++
src/containers/comment/index.js | 4 ++++
src/i18n/index.js | 3 ++-
src/utils/list-to-tree/index.js | 6 ++++--
6 files changed, 24 insertions(+), 9 deletions(-)
diff --git a/src/components/comment-form/index.js b/src/components/comment-form/index.js
index 1340f57c9..416063613 100644
--- a/src/components/comment-form/index.js
+++ b/src/components/comment-form/index.js
@@ -1,7 +1,6 @@
import React, { useState, useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import { cn as bem } from '@bem-react/classname';
-import useTranslate from '../../hooks/use-translate';
import { useNavigate } from 'react-router-dom';
import './style.css';
import Button from '../button';
@@ -15,9 +14,9 @@ function FormComment({
exists,
setFormCommentIsActive = () => {},
currentCommentId,
+ t
}) {
const cn = bem('FormComment');
- const { t } = useTranslate();
const navigate = useNavigate();
const [text, setText] = useState('');
const formRef = useRef(null);
diff --git a/src/components/comment-item/index.js b/src/components/comment-item/index.js
index ab2349365..3d1284c4c 100644
--- a/src/components/comment-item/index.js
+++ b/src/components/comment-item/index.js
@@ -2,12 +2,10 @@ import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
import { cn as bem } from '@bem-react/classname';
import FormComment from '../comment-form';
-import useTranslate from '../../hooks/use-translate';
import './style.css';
function ItemComment(props) {
const cn = bem('ItemComment');
- const { t } = useTranslate();
const computedLevel = useMemo(() => {
if (props.level > 10) return 10;
@@ -34,7 +32,13 @@ function ItemComment(props) {
return (
-
{props.name}
+
+ {props.name}
+
{correctDatetime}
{props.text}
@@ -44,13 +48,14 @@ function ItemComment(props) {
{props.formAnswerIsActive && props.index1 === props.index2 && (
)}
diff --git a/src/components/comment-item/style.css b/src/components/comment-item/style.css
index 097ed5d07..5c0d62964 100644
--- a/src/components/comment-item/style.css
+++ b/src/components/comment-item/style.css
@@ -56,6 +56,10 @@
font-size: 12px;
}
+.ItemComment-autho {
+ color: rgba(75, 85, 99, 1);
+}
+
.ItemComment-datetime {
font-size: 12px;
color: #666666;
diff --git a/src/containers/comment/index.js b/src/containers/comment/index.js
index a891f0883..6d230efaa 100644
--- a/src/containers/comment/index.js
+++ b/src/containers/comment/index.js
@@ -84,6 +84,7 @@ function Comments() {
[selectRedux.comments],
),
};
+console.log(options.comments);
return (
@@ -109,6 +110,8 @@ function Comments() {
addForm={callbacks.addForm}
sendComment={callbacks.sendComment}
currentCommentId={selectRedux.currentCommentId}
+ nameFromSession={select.name}
+ t={t}
/>
),
)}
@@ -121,6 +124,7 @@ function Comments() {
sendComment={callbacks.sendComment}
type="article"
exists={select.exists}
+ t={t}
/>
)}
diff --git a/src/i18n/index.js b/src/i18n/index.js
index 6d0d205af..45ce521a2 100644
--- a/src/i18n/index.js
+++ b/src/i18n/index.js
@@ -2,7 +2,7 @@ import * as translations from './translations';
class i18nService {
constructor() {
- this.lang = 'ru';
+ this.lang = localStorage.getItem('lang') || 'ru';
this.listeners = new Set();
}
@@ -10,6 +10,7 @@ class i18nService {
setLang(lang) {
if (this.lang !== lang) {
this.lang = lang;
+ localStorage.setItem('lang', lang);
this.sentNotify(lang);
}
}
diff --git a/src/utils/list-to-tree/index.js b/src/utils/list-to-tree/index.js
index fb4d20a66..265d2f9f0 100644
--- a/src/utils/list-to-tree/index.js
+++ b/src/utils/list-to-tree/index.js
@@ -4,7 +4,9 @@
* @param [key] {String} Свойство с первичным ключом
* @returns {Array} Корневые узлы
*/
-export default function listToTree(list, key = '_id') {
+export default function listToTree(list, key = '_id', type = '_type') {
+ console.log(list);
+
let trees = {};
let roots = {};
for (const item of list) {
@@ -19,7 +21,7 @@ export default function listToTree(list, key = '_id') {
}
// Если элемент имеет родителя, то добавляем его в подчиненные родителя
- if (item.parent?.[key]) {
+ if (item.parent?.[key] && item.parent?.[type] !== 'article') {
// Если родителя ещё нет в индексе, то индекс создаётся, ведь _id родителя известен
if (!trees[item.parent[key]]) {
trees[item.parent[key]] = { children: [] };
From dace2eae4233e0c1ae9e993db6b21ab87e2fa384 Mon Sep 17 00:00:00 2001
From: PonomarevAlexx <136852344+PonomarevAlexx@users.noreply.github.com>
Date: Mon, 21 Apr 2025 15:18:01 +0300
Subject: [PATCH 4/4] fixed
---
src/containers/comment/index.js | 1 -
src/utils/list-to-tree/index.js | 1 -
2 files changed, 2 deletions(-)
diff --git a/src/containers/comment/index.js b/src/containers/comment/index.js
index 6d230efaa..acd36769b 100644
--- a/src/containers/comment/index.js
+++ b/src/containers/comment/index.js
@@ -84,7 +84,6 @@ function Comments() {
[selectRedux.comments],
),
};
-console.log(options.comments);
return (
diff --git a/src/utils/list-to-tree/index.js b/src/utils/list-to-tree/index.js
index 265d2f9f0..23f98b4f8 100644
--- a/src/utils/list-to-tree/index.js
+++ b/src/utils/list-to-tree/index.js
@@ -5,7 +5,6 @@
* @returns {Array} Корневые узлы
*/
export default function listToTree(list, key = '_id', type = '_type') {
- console.log(list);
let trees = {};
let roots = {};