Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
913f9a3
Добавила стили и ключи с переводом
gudrum1983 Apr 19, 2025
ca13722
Задание 1
gudrum1983 Apr 19, 2025
8ad2a5a
Задание 2 - Добавила ключи в словари
gudrum1983 Apr 19, 2025
5cb424b
Задание 2 переписала контекст на сервис
gudrum1983 Apr 19, 2025
7046675
Задание обновила импорты
gudrum1983 Apr 19, 2025
72a2c4a
Рефакторинг 1 - пофиксить перенос длинных слов в комментарии и бескон…
gudrum1983 Apr 20, 2025
9e7ea83
Рефакторинг 2
gudrum1983 Apr 20, 2025
62ea23c
Рефакторинг 3
gudrum1983 Apr 20, 2025
3e9797b
fix 1 - удалила ненужный литерал из даты
gudrum1983 Apr 21, 2025
a8da06f
fix 3 - добавила стили текста в textarea и убрала стили дефолтного фо…
gudrum1983 Apr 21, 2025
e5c48c9
fix 4, 6 - проверка на пустой комментарий, формат даты, кнопка отмены
gudrum1983 Apr 21, 2025
20a63ec
fix 9 - удалила передачу токена
gudrum1983 Apr 21, 2025
2143ce9
fix 7 - возврат к текущему комментарию после логина
gudrum1983 Apr 21, 2025
46746cd
fix 1, 5, 10 - вернула отступы как были, открытие формы комментария ч…
gudrum1983 Apr 22, 2025
1afcd6e
fix - сломала скролл после авторизации, пересмотреть перерендеры и за…
gudrum1983 Apr 22, 2025
350a63e
рефакторинг, нейминг и консоль логи
gudrum1983 Apr 22, 2025
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
4 changes: 2 additions & 2 deletions api-examples/comments.http
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ X-Token: 7ee15209d8429544dea8123fbdae254f5f79e6da5d720fec3127d9385b6eb9bc
# Создание ответа на коммент коммента
POST http://query.rest/api/v1/comments
Content-Type: application/json
X-Token: 7ee15209d8429544dea8123fbdae254f5f79e6da5d720fec3127d9385b6eb9bc
X-Token: 40717d1c056933a15c15a0d8ccd6684cd8ff2805b845d9810a4446c85d2f93c4

{
"text": "Первый ответ на коммент!",
"parent": {"_id": "670429839c74519426f378bd", "_type": "comment"}
"parent": {"_id": "68056df17e843dad89610a98", "_type": "comment"}
}
16 changes: 10 additions & 6 deletions src/app/article/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { memo, useCallback } from 'react';
import { useParams } from 'react-router-dom';
import useStore from '../../hooks/use-store';
import useTranslate from '../../hooks/use-translate';
import useInit from '../../hooks/use-init';
import PageLayout from '../../components/page-layout';
import Head from '../../components/head';
Expand All @@ -13,20 +12,26 @@ 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 ArticleComments from '../../containers/article-comments';
import useLocale from '../../hooks/use-locale';


function Article() {
const store = useStore();

const dispatch = useDispatch();
// Параметры из пути /articles/:id

const { t, locale} = useLocale()

const params = useParams();

useInit(() => {
//store.actions.article.load(params.id);
dispatch(articleActions.load(params.id));
}, [params.id]);
dispatch(articleActions.load(params.id, locale));
dispatch(commentsActions.load(params.id));
}, [params.id, locale]);

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

const { t } = useTranslate();

const callbacks = {
// Добавление в корзину
addToBasket: useCallback(_id => store.actions.basket.addToBasket(_id), [store]),
Expand All @@ -55,6 +58,7 @@ function Article() {
<Navigation />
<Spinner active={select.waiting}>
<ArticleCard article={select.article} onAdd={callbacks.addToBasket} t={t} />
<ArticleComments/>
</Spinner>
</PageLayout>
</>
Expand Down
12 changes: 6 additions & 6 deletions src/app/basket/index.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { memo, useCallback } from 'react';
import { useDispatch, useStore as useStoreRedux } from 'react-redux';
import { useDispatch } from 'react-redux';
import useStore from '../../hooks/use-store';
import useSelector from '../../hooks/use-selector';
import useInit from '../../hooks/use-init';
import useTranslate from '../../hooks/use-translate';
import ItemBasket from '../../components/item-basket';
import List from '../../components/list';
import ModalLayout from '../../components/modal-layout';
import BasketTotal from '../../components/basket-total';
import modalsActions from '../../store-redux/modals/actions';
import useLocale from '../../hooks/use-locale';



function Basket() {
const store = useStore();
const dispatch = useDispatch();

const {locale, t} = useLocale()
const select = useSelector(state => ({
list: state.basket.list,
amount: state.basket.amount,
Expand All @@ -30,12 +31,11 @@ function Basket() {
}, [store]),
};

const { t } = useTranslate();

const renders = {
itemBasket: useCallback(
item => (
<ItemBasket
locale={locale}
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Передаю локаль, что бы можно было отображать товар в корзине в зависимости от выбранного языка

item={item}
link={`/articles/${item._id}`}
onRemove={callbacks.removeFromBasket}
Expand Down
7 changes: 4 additions & 3 deletions src/app/login/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { memo, useCallback, useState } from 'react';
import useTranslate from '../../hooks/use-translate';
import Head from '../../components/head';
import LocaleSelect from '../../containers/locale-select';
import Navigation from '../../containers/navigation';
Expand All @@ -14,9 +13,11 @@ import useSelector from '../../hooks/use-selector';
import useInit from '../../hooks/use-init';
import HeadLayout from '../../components/head-layout';
import Form from '../../components/form';
import useLocale from '../../hooks/use-locale';


function Login() {
const { t } = useTranslate();
const { t } = useLocale()
const location = useLocation();
const navigate = useNavigate();
const store = useStore();
Expand Down Expand Up @@ -51,7 +52,7 @@ function Login() {
location.state?.back && location.state?.back !== location.pathname
? location.state?.back
: '/';
navigate(back);
navigate(back, {state: {replyTo: location.state?.replyTo}});
});
},
[data, location.state],
Expand Down
8 changes: 4 additions & 4 deletions src/app/main/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { memo } from 'react';
import useStore from '../../hooks/use-store';
import useTranslate from '../../hooks/use-translate';
import useInit from '../../hooks/use-init';
import Navigation from '../../containers/navigation';
import PageLayout from '../../components/page-layout';
Expand All @@ -10,20 +9,21 @@ import CatalogList from '../../containers/catalog-list';
import LocaleSelect from '../../containers/locale-select';
import TopHead from '../../containers/top-head';
import HeadLayout from '../../components/head-layout';
import useLocale from '../../hooks/use-locale';

function Main() {
const store = useStore();

const { locale, t } = useLocale()

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

const { t } = useTranslate();

return (
<>
<HeadLayout>
Expand Down
7 changes: 4 additions & 3 deletions src/app/profile/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { memo } from 'react';
import useStore from '../../hooks/use-store';
import useSelector from '../../hooks/use-selector';
import useTranslate from '../../hooks/use-translate';
import useInit from '../../hooks/use-init';
import PageLayout from '../../components/page-layout';
import Head from '../../components/head';
Expand All @@ -11,6 +10,8 @@ import LocaleSelect from '../../containers/locale-select';
import TopHead from '../../containers/top-head';
import ProfileCard from '../../components/profile-card';
import HeadLayout from '../../components/head-layout';
import useLocale from '../../hooks/use-locale';


function Profile() {
const store = useStore();
Expand All @@ -24,7 +25,7 @@ function Profile() {
waiting: state.profile.waiting,
}));

const { t } = useTranslate();
const { t } = useLocale()

return (
<>
Expand All @@ -37,7 +38,7 @@ function Profile() {
<PageLayout>
<Navigation />
<Spinner active={select.waiting}>
<ProfileCard data={select.profile} />
<ProfileCard data={select.profile} t={t} />
</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.country')}:</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.releaseYear')}:</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/article-card/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
display: flex;
flex-direction: column;
gap: 24px;
padding-block: 24px;
padding-top: 24px;
}

.ArticleCard-prop-wrapper {
Expand Down
5 changes: 3 additions & 2 deletions src/components/button/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import PropTypes from 'prop-types';
import { cn as bem } from '@bem-react/classname';
import './style.css';

function Button({ onClick = () => {}, title, style, type = 'button' }) {
function Button({ onClick = () => {}, title, style, type = 'button', disabled = false }) {
const cn = bem('Button');

return (
<div className={cn()}>
<button type={type} className={cn({ style })} onClick={() => onClick()}>{title}</button>
<button type={type} className={cn({ style })} onClick={() => onClick()} disabled={disabled}>{title}</button>
</div>
);
}
Expand All @@ -18,6 +18,7 @@ Button.propTypes = {
title: PropTypes.string,
style: PropTypes.oneOf(['text', 'primary', 'delete', 'outline']),
type: PropTypes.oneOf(['button', 'submit']),
disabled: PropTypes.bool,
};

export default memo(Button);
9 changes: 8 additions & 1 deletion src/components/button/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
border-color: var(--primary);
color: var(--primary);
}

&:disabled&:hover {
color: var(--second-text);
border-color: var(--filter-border);
background-color: var(--filter-border);
}
}

.Button_style_delete {
Expand Down Expand Up @@ -34,8 +40,9 @@
.Button_style_text {
padding: 0;
border: none;
color: var(--primary);

&:hover {
color: var(--primary);
opacity: 0.6;
}
}
69 changes: 69 additions & 0 deletions src/components/comment-action/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { memo } from 'react';
import PropTypes from 'prop-types';
import { cn as bem } from '@bem-react/classname';
import './style.css';
import Button from '../button';
import { Link } from 'react-router-dom';

function CommentAction(props) {
const {
id='',
t = text => text,
onAdd = () => {},
setValue = () => {},
cancel = () => {},
value = '',
isReply = false,
auth = false,
link = '/login',
backLink = '',
} = props;
const cn = bem('CommentAction');

const label = isReply ? t('comment.newReply') : t('comment.newComment');

const onChangeHandler = event => {
setValue(event.target.value);
};


if (!auth) {
return (
<div {...(isReply ? { id: 'reply' } : {})} className={cn({type: 'alert'})}>
<Link to={link} state={{back: backLink, replyTo: id}}>{t('comment.authHint.link')}</Link>{t('comment.authHint.text')}
</div>
);
}


return (
<div {...(isReply ? { id: 'reply' } : {})} className={cn(isReply ? { type: 'reply' } : {})}>
<label htmlFor="comment">{label}</label>
<textarea id="comment"
name="comment"
onChange={onChangeHandler}
value={value}/>
<div className={cn('controls')}>
<Button title={t('comment.send')}
disabled={!value.trim()}
style={'primary'}
onClick={() => { onAdd(); cancel(); }}/>
{isReply && <Button title={t('comment.cancel')} style={'outline'} onClick={cancel}/>}
</div>
</div>
);
}

CommentAction.propTypes = {
onAdd: PropTypes.func,
t: PropTypes.func,
id: PropTypes.string,
value: PropTypes.string,
isReply: PropTypes.bool,
auth: PropTypes.bool,
link: PropTypes.string,
backLink: PropTypes.string,
cancel: PropTypes.func,
};

export default memo(CommentAction);
Loading