Skip to content

Commit

Permalink
feat: add widget with additional article information
Browse files Browse the repository at this point in the history
  • Loading branch information
sashtje committed Oct 13, 2023
1 parent 5afc232 commit e748eca
Show file tree
Hide file tree
Showing 26 changed files with 243 additions and 25 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion json-server/db.json
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,7 @@
"isAppRedesigned": true
},
"jsonSettings": {
"theme": "app_light_theme",
"theme": "app_dark_theme",
"isFirstVisit": true,
"settingsPageHasBeenOpen": false,
"isArticlesPageWasOpened": true
Expand Down
4 changes: 3 additions & 1 deletion public/locales/en/articles.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,7 @@
"Оставьте свой отзыв о статье": "Leave your feedback on the article",
"Оценка статей скоро появится!": "Article ratings coming soon!",
"Добро пожаловать на страницу статей": "Welcome to the articles page",
"Здесь Вы можете искать и просматривать статьи на различные темы": "Here you can search and view articles on various topics"
"Здесь Вы можете искать и просматривать статьи на различные темы": "Here you can search and view articles on various topics",
"Просмотров_one": "{{count}} view",
"Просмотров_other": "{{count}} views"
}
5 changes: 4 additions & 1 deletion public/locales/ru/articles.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,8 @@
"Оставьте свой отзыв о статье": "Оставьте свой отзыв о статье",
"Оценка статей скоро появится!": "Оценка статей скоро появится!",
"Добро пожаловать на страницу статей": "Добро пожаловать на страницу статей",
"Здесь Вы можете искать и просматривать статьи на различные темы": "Здесь Вы можете искать и просматривать статьи на различные темы"
"Здесь Вы можете искать и просматривать статьи на различные темы": "Здесь Вы можете искать и просматривать статьи на различные темы",
"Просмотров_one": "{{count}} просмотр",
"Просмотров_few": "{{count}} просмотра",
"Просмотров_many": "{{count}} просмотров"
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ export const fetchArticleById = createAsyncThunk<Article, string, ThunkConfig<st
const { extra, rejectWithValue } = thunkAPI;

try {
const response = await extra.api.get<Article>(`/articles/${articleId}`);
const response = await extra.api.get<Article>(`/articles/${articleId}`, {
params: {
_expand: 'user',
},
});

if (!response.data) {
throw new Error();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.card {
width: 264px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { ComponentMeta, ComponentStory } from '@storybook/react';

import { AdditionalInfoContainer } from './AdditionalInfoContainer';

export default {
title: 'shared/AdditionalInfoContainer',
component: AdditionalInfoContainer,
argTypes: {
backgroundColor: { control: 'color' },
},
} as ComponentMeta<typeof AdditionalInfoContainer>;

const Template: ComponentStory<typeof AdditionalInfoContainer> = (args) => <AdditionalInfoContainer {...args} />;

export const Normal = Template.bind({});
Normal.args = {};
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { memo, useCallback } from 'react';
import { useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom';

import { ArticalAdditionalInfo } from '@/widgets/ArticalAdditionalInfo';
import { Card } from '@/shared/ui/redesigned/Card';
import { getArticleDetails } from '@/entities/Article';
import { classNames } from '@/shared/lib/classNames';
import { getRouteArticleEdit } from '@/shared/const/router';
import { Skeleton } from '@/shared/ui/redesigned/Skeleton';
import { VStack } from '@/shared/ui/redesigned/Stack';

import cls from './AdditionalInfoContainer.module.scss';

interface AdditionalInfoContainerProps {
className?: string;
}

export const AdditionalInfoContainer = memo((props: AdditionalInfoContainerProps) => {
const { className } = props;
const article = useSelector(getArticleDetails);
const navigate = useNavigate();

const onEditArticle = useCallback(() => {
if (article?.id) {
navigate(getRouteArticleEdit(article.id));
}
}, [navigate, article]);

if (!article) {
return (
<Card padding="24" borderRadius="round" className={classNames(cls.card, {}, [className])}>
<VStack gap="32">
<Skeleton width={200} height={24} />
<Skeleton width={200} height={38} />
<Skeleton width={200} height={24} />
</VStack>
</Card>
);
}

return (
<Card padding="24" borderRadius="round" className={classNames(cls.card, {}, [className])}>
<ArticalAdditionalInfo
onEdit={onEditArticle}
author={article.user}
createdAt={article.createdAt}
views={article.views}
/>
</Card>
);
});

AdditionalInfoContainer.displayName = 'AdditionalInfoContainer';
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ import { ArticleRecommendationsList } from '@/features/articleRecommendationsLis
import { ArticleRating } from '@/features/articleRating';
import { ToggleFeatures } from '@/shared/lib/features';
import { Card } from '@/shared/ui/deprecated/Card';
import { StickyContentLayout } from '@/shared/layouts';

import { DetailsContainer } from '../DetailsContainer/DetailsContainer';
import { AdditionalInfoContainer } from '../AdditionalInfoContainer/AdditionalInfoContainer';
import { ArticleDetailsComments } from '../ArticleDetailsComments/ArticleDetailsComments';
import { ArticleDetailsPageHeader } from '../../ui/ArticleDetailsPageHeader/ArticleDetailsPageHeader';
import { articleDetailsPageReducer } from '../../model/slices';
Expand Down Expand Up @@ -44,23 +47,42 @@ export const ArticleDetailsPage = memo((props: ArticleDetailsPageProps) => {

return (
<DynamicModuleLoader reducers={reducersList} removeAfterUnmount>
<Page className={classNames(cls.articleDetailsPage, {}, [className])}>
<VStack gap="16" max>
<ArticleDetailsPageHeader />
<ToggleFeatures
feature="isAppRedesigned"
on={
<StickyContentLayout
content={
<Page className={classNames(cls.articleDetailsPage, {}, [className])}>
<VStack gap="16" max>
<DetailsContainer />

<ArticleRating articleId={id} />

<ArticleDetails id={id} />
<ArticleRecommendationsList />

<ToggleFeatures
feature="isArticleRatingEnabled"
on={<ArticleRating articleId={id} />}
off={<Card>{t('Оценка статей скоро появится!')}</Card>}
<ArticleDetailsComments id={id} />
</VStack>
</Page>
}
right={<AdditionalInfoContainer />}
/>
}
off={
<Page className={classNames(cls.articleDetailsPage, {}, [className])}>
<VStack gap="16" max>
<ArticleDetailsPageHeader />

<ArticleRecommendationsList />
<ArticleDetails id={id} />

<ArticleDetailsComments id={id} />
</VStack>
</Page>
<Card>{t('Оценка статей скоро появится!')}</Card>

<ArticleRecommendationsList />

<ArticleDetailsComments id={id} />
</VStack>
</Page>
}
/>
</DynamicModuleLoader>
);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { ComponentMeta, ComponentStory } from '@storybook/react';

import { DetailsContainer } from './DetailsContainer';

export default {
title: 'shared/DetailsContainer',
component: DetailsContainer,
argTypes: {
backgroundColor: { control: 'color' },
},
} as ComponentMeta<typeof DetailsContainer>;

const Template: ComponentStory<typeof DetailsContainer> = (args) => <DetailsContainer {...args} />;

export const Normal = Template.bind({});
Normal.args = {};
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { memo } from 'react';
import { useParams } from 'react-router-dom';

import { ArticleDetails } from '@/entities/Article';
import { Card } from '@/shared/ui/redesigned/Card';

interface DetailsContainerProps {
className?: string;
}

export const DetailsContainer = memo((props: DetailsContainerProps) => {
const { className } = props;
const { id } = useParams<{ id: string }>();

return (
<Card fullwidth className={className} padding="24" borderRadius="round">
<ArticleDetails id={id!} />
</Card>
);
});

DetailsContainer.displayName = 'DetailsContainer';
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ export const StickyContentLayout = memo((props: StickyContentLayoutProps) => {

return (
<div className={classNames(cls.stickyContentLayout, {}, [className])}>
{right && <div className={cls.left}>{left}</div>}
{left && <div className={cls.left}>{left}</div>}

<div className={cls.content}>{content}</div>

{left && <div className={cls.right}>{right}</div>}
{right && <div className={cls.right}>{right}</div>}
</div>
);
});
Expand Down
4 changes: 4 additions & 0 deletions src/shared/ui/redesigned/Card/ui/Card.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
width: 100%;
}

.fullheight {
height: 100%;
}

.gap_0 {
padding: 0;
}
Expand Down
13 changes: 7 additions & 6 deletions src/shared/ui/redesigned/Card/ui/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface CardProps extends HTMLAttributes<HTMLDivElement> {
children: ReactNode;
variant?: CardVariant;
fullwidth?: boolean;
fullheight?: boolean;
padding?: CardPadding;
borderRadius?: CardBorder;
}
Expand All @@ -30,6 +31,7 @@ export const Card = memo((props: CardProps) => {
children,
variant = 'normal',
fullwidth = false,
fullheight = false,
padding = '8',
borderRadius = 'default',
...otherProps
Expand All @@ -39,12 +41,11 @@ export const Card = memo((props: CardProps) => {

return (
<div
className={classNames(cls.card, { [cls.fullwidth]: fullwidth }, [
className,
cls[variant],
cls[paddingClass],
cls[borderRadius],
])}
className={classNames(
cls.card,
{ [cls.fullwidth]: fullwidth, [cls.fullheight]: fullheight },
[className, cls[variant], cls[paddingClass], cls[borderRadius]],
)}
{...otherProps}
>
{children}
Expand Down
1 change: 1 addition & 0 deletions src/widgets/ArticalAdditionalInfo/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ArticalAdditionalInfo } from './ui/ArticalAdditionalInfo';
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { ComponentMeta, ComponentStory } from '@storybook/react';

import { article } from '@/entities/Article/testing';

import { ArticalAdditionalInfo } from './ArticalAdditionalInfo';

export default {
title: 'shared/ArticalAdditionalInfo',
component: ArticalAdditionalInfo,
argTypes: {
backgroundColor: { control: 'color' },
},
} as ComponentMeta<typeof ArticalAdditionalInfo>;

const Template: ComponentStory<typeof ArticalAdditionalInfo> = (args) => (
<ArticalAdditionalInfo {...args} />
);

export const Normal = Template.bind({});
Normal.args = {
author: article.user,
views: article.views,
createdAt: article.createdAt,
};
46 changes: 46 additions & 0 deletions src/widgets/ArticalAdditionalInfo/ui/ArticalAdditionalInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';

import { classNames } from '@/shared/lib/classNames';
import { User } from '@/entities/User';
import { HStack, VStack } from '@/shared/ui/redesigned/Stack';
import { Avatar } from '@/shared/ui/redesigned/Avatar';
import { Text } from '@/shared/ui/redesigned/Text';
import { Button } from '@/shared/ui/redesigned/Button';
import { getCanEditArticle } from '@/pages/ArticleDetailsPage/model/selectors/article';

import cls from './ArticalAdditionalInfo.module.scss';

interface ArticalAdditionalInfoProps {
className?: string;
author: User;
createdAt: string;
views: number;
onEdit: () => void;
}

export const ArticalAdditionalInfo = memo((props: ArticalAdditionalInfoProps) => {
const { className, author, views, createdAt, onEdit } = props;
const canEditArticle = useSelector(getCanEditArticle);

const { t } = useTranslation('articles');

return (
<VStack gap="32" className={classNames(cls.articalAdditionalInfo, {}, [className])}>
<HStack gap="8">
<Avatar src={author.avatar} size={32} />

<Text text={author.username} bold />

<Text text={createdAt} />
</HStack>

{canEditArticle && <Button onClick={onEdit}>{t('Редактировать')}</Button>}

<Text text={t('Просмотров', { count: views })} />
</VStack>
);
});

ArticalAdditionalInfo.displayName = 'ArticalAdditionalInfo';
2 changes: 1 addition & 1 deletion src/widgets/ArticlesFilters/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { ArticlesFilters } from './ArticlesFilters';
export { ArticlesFilters } from './ui/ArticlesFilters';

0 comments on commit e748eca

Please sign in to comment.