Skip to content

Commit

Permalink
feat: add tabs filters
Browse files Browse the repository at this point in the history
  • Loading branch information
TomatoVan committed Feb 3, 2024
1 parent 53dd131 commit ac3a03e
Show file tree
Hide file tree
Showing 22 changed files with 243 additions and 21 deletions.
5 changes: 5 additions & 0 deletions extractedTranslations/en/translation.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
{
"": "",
"All": "",
"Articles not found": "",
"Back to list": "",
"Cancel": "",
"Choose country": "",
"Choose currency": "",
"Comments": "",
"Economics": "",
"Edit": "",
"Enter ": "",
"Enter comment text": "",
"Enter cooment text": "",
"Error with getting article data": "",
"Error with getting profile data": "",
"IT": "",
"Incorrect age": "",
"Incorrect country": "",
"Incorrect user data": "",
Expand All @@ -25,6 +29,7 @@
}
},
"Save": "",
"Science": "",
"Search": "",
"Send": "",
"Server error": "",
Expand Down
4 changes: 3 additions & 1 deletion src/entities/Article/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ export type { ArticleDetailsSchema } from './model/types/articleDetailsSchema';
export { getArticlesDetailsData } from './model/selectors/articleDetails';
export { ArticleList } from './ui/ArticleList/ArticleList';
export { ArticleSortSelector } from './ui/ArticleSortSelector/ArticleSortSelector';
export { Article, ArticleView, ArticleSortField } from './model/types/article';
export {
Article, ArticleView, ArticleSortField, ArticleType,
} from './model/types/article';
3 changes: 2 additions & 1 deletion src/entities/Article/model/types/article.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ export type ArticleBlock = ArticleCodeBlock | ArticleImageBlock | ArticleTextBlo
export enum ArticleType {
IT = 'IT',
SCIENCE = 'SCIENCE',
ECONOMICS = 'ECONOMICS'
ECONOMICS = 'ECONOMICS',
ALL = 'ALL'
}

export enum ArticleView {
Expand Down
10 changes: 10 additions & 0 deletions src/entities/Article/ui/ArticleList/ArticleList.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { classNames } from 'shared/lib/classNames/classNames';
import { memo } from 'react';
import { Text, TextSize } from 'shared/ui/Text/Text';
import { useTranslation } from 'react-i18next';
import { ArticleListItemSkeleton } from '../../ui/ArticleListItem/ArticleListItemSkeleton';
import { ArticleListItem } from '../ArticleListItem/ArticleListItem';
import { Article, ArticleView } from '../../model/types/article';
Expand All @@ -26,6 +28,8 @@ export const ArticleList = memo((props: ArticleListProps) => {
isLoading,
} = props;

const { t } = useTranslation();

const renderArticle = (article: Article) => (
<ArticleListItem
article={article}
Expand All @@ -35,6 +39,12 @@ export const ArticleList = memo((props: ArticleListProps) => {
/>
);

if (!isLoading && !articles.length) {
return (
<Text size={TextSize.L} title={t('Articles not found')} />
);
}

return (
<div className={classNames(cls.ArticleList, {}, [className, cls[view]])}>
{articles.length > 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ComponentStory, ComponentMeta } from '@storybook/react';
import { ArticleSortSelector } from './ArticleSortSelector';

export default {
title: 'shared/ArticleSortSelector',
title: 'entities/ArticleSortSelector',
component: ArticleSortSelector,
argTypes: {
backgroundColor: { control: 'color' },
Expand Down
1 change: 1 addition & 0 deletions src/features/ArticleTypeTabs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ArticleTypeTabs } from './ui/ArticleTypeTabs';
17 changes: 17 additions & 0 deletions src/features/ArticleTypeTabs/ui/ArticleTypeTabs.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';

import { ArticleTypeTabs } from './ArticleTypeTabs';

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

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

export const Normal = Template.bind({});
Normal.args = {};
49 changes: 49 additions & 0 deletions src/features/ArticleTypeTabs/ui/ArticleTypeTabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { classNames } from 'shared/lib/classNames/classNames';
import { useTranslation } from 'react-i18next';
import { memo, useCallback, useMemo } from 'react';
import { TabItem, Tabs } from 'shared/ui/Tabs/Tabs';
import { ArticleType } from 'entities/Article';

interface ArticleTypeTabsProps {
className?: string;
value: ArticleType;
onChangeType: (type: ArticleType) => void;
}

export const ArticleTypeTabs = memo((props: ArticleTypeTabsProps) => {
const { className, value, onChangeType } = props;
const { t } = useTranslation();

const typeTabs = useMemo<TabItem[]>(() => [
{
value: ArticleType.ALL,
content: t('All'),
},
{
value: ArticleType.IT,
content: t('IT'),
},
{
value: ArticleType.ECONOMICS,
content: t('Economics'),
},
{
value: ArticleType.SCIENCE,
content: t('Science'),
},

], [t]);

const onTabClick = useCallback((tab: TabItem) => {
onChangeType(tab.value as ArticleType);
}, [onChangeType]);

return (
<Tabs
className={classNames('', {}, [className])}
tabs={typeTabs}
value={value}
onTabClick={onTabClick}
/>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ComponentStory, ComponentMeta } from '@storybook/react';
import { ArticleViewSelector } from './ArticleViewSelector';

export default {
title: 'shared/ArticleViewSelector',
title: 'features/ArticleViewSelector',
component: ArticleViewSelector,
argTypes: {
backgroundColor: { control: 'color' },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { StateSchema } from 'app/providers/StoreProvider';
import { ArticleSortField, ArticleView } from '../../../../entities/Article';
import { ArticleSortField, ArticleType, ArticleView } from '../../../../entities/Article';

export const getArticlesPageisLoading = (state: StateSchema) => state.articlesPage?.isLoading || false;
export const getArticlesPageError = (state: StateSchema) => state.articlesPage?.error;
Expand All @@ -11,3 +11,4 @@ export const getArticlesPageInited = (state: StateSchema) => state.articlesPage?
export const getArticlesPageOrder = (state: StateSchema) => state.articlesPage?.order ?? 'asc';
export const getArticlesPageSort = (state: StateSchema) => state.articlesPage?.sort ?? ArticleSortField.CREATED;
export const getArticlesPageSearch = (state: StateSchema) => state.articlesPage?.search ?? '';
export const getArticlesPageType = (state: StateSchema) => state.articlesPage?.type ?? ArticleType.ALL;
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { createAsyncThunk } from '@reduxjs/toolkit';
import { ThunkConfig } from 'app/providers/StoreProvider';
import { Article } from 'entities/Article';
import { Article, ArticleType } from 'entities/Article';
import { addQueryParams } from 'shared/lib/url/addQueryParams/addQueryParams';
import {
getArticlesPageLimit,
getArticlesPageNum,
getArticlesPageOrder,
getArticlesPageSearch,
getArticlesPageSort,
} from 'pages/ArticlesPage/model/selectors/articlesPageSelectors';
import { addQueryParams } from 'shared/lib/url/addQueryParams/addQueryParams';
getArticlesPageType,
} from '../../selectors/articlesPageSelectors';

interface fetchArticlesListProps {
replace?: boolean;
replace?: boolean;
}

export const fetchArticlesList = createAsyncThunk<
Expand All @@ -26,10 +27,11 @@ export const fetchArticlesList = createAsyncThunk<
const order = getArticlesPageOrder(getState());
const search = getArticlesPageSearch(getState());
const page = getArticlesPageNum(getState());
const type = getArticlesPageType(getState());

try {
addQueryParams({
sort, order, search,
sort, order, search, type,
});

const response = await extra.api.get<Article[]>('/articles', {
Expand All @@ -40,6 +42,7 @@ export const fetchArticlesList = createAsyncThunk<
_sort: sort,
_order: order,
q: search,
type: type === ArticleType.ALL ? undefined : type,

},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { ThunkConfig } from 'app/providers/StoreProvider';
import { getArticlesPageInited } from 'pages/ArticlesPage/model/selectors/articlesPageSelectors';
import { articlesPageActions } from 'pages/ArticlesPage/model/slices/articlesPageSlice';
import { fetchArticlesList } from 'pages/ArticlesPage/model/services/fetchArticlesList/fetchArticlesList';
import { ArticleSortField } from 'entities/Article';
import { SortOrder } from 'shared/types';
import { ArticleSortField } from '../../../../../entities/Article';

export const initArticlesPage = createAsyncThunk<
void,
Expand Down
9 changes: 8 additions & 1 deletion src/pages/ArticlesPage/model/slices/articlesPageSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import {
import { StateSchema } from 'app/providers/StoreProvider';
import { ARTICLE_VIEW_LOCALSTORAGE_KEY } from 'shared/const/localstorage';
import { SortOrder } from 'shared/types';
import { ArticleSortField } from '../../../../entities/Article/model/types/article';
import {
ArticleSortField,
ArticleType,
} from '../../../../entities/Article/model/types/article';
import { ArticlesPageSchema } from '../types/articlesPageSchema';
import { Article, ArticleView } from '../../../../entities/Article';
import { fetchArticlesList } from '../services/fetchArticlesList/fetchArticlesList';
Expand Down Expand Up @@ -34,6 +37,7 @@ const articlesPageSlice = createSlice({
sort: ArticleSortField.CREATED,
search: '',
order: 'asc',
type: ArticleType.ALL,
}),
reducers: {
setView: (state, action: PayloadAction<ArticleView>) => {
Expand All @@ -49,6 +53,9 @@ const articlesPageSlice = createSlice({
setSort: (state, action: PayloadAction<ArticleSortField>) => {
state.sort = action.payload;
},
setType: (state, action: PayloadAction<ArticleType>) => {
state.type = action.payload;
},
setSearch: (state, action: PayloadAction<string>) => {
state.search = action.payload;
},
Expand Down
7 changes: 4 additions & 3 deletions src/pages/ArticlesPage/model/types/articlesPageSchema.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { EntityState } from '@reduxjs/toolkit';
import { Article, ArticleView } from 'entities/Article';
import {
Article, ArticleView, ArticleSortField, ArticleType,
} from 'entities/Article';
import { SortOrder } from 'shared/types';
import { ArticleSortField } from 'entities/Article/model/types/article';

export interface ArticlesPageSchema extends EntityState<Article> {
isLoading?: boolean;
Expand All @@ -16,7 +17,7 @@ export interface ArticlesPageSchema extends EntityState<Article> {
order: SortOrder;
sort:ArticleSortField;
search: string;

type: ArticleType;
// data already inited or not
_inited: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@
.search {
margin-top: 16px;
}

.tabs {
margin-top: 16px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ComponentStory, ComponentMeta } from '@storybook/react';
import { ArticlesPageFilters } from './ArticlesPageFilters';

export default {
title: 'shared/ArticlesPageFilters',
title: 'pages/ArticlesPageFilters',
component: ArticlesPageFilters,
argTypes: {
backgroundColor: { control: 'color' },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
import { classNames } from 'shared/lib/classNames/classNames';
import { memo, useCallback } from 'react';
import { memo, useCallback, useMemo } from 'react';
import { ArticleViewSelector } from 'features/ArticleViewSelector';
import { useAppDispatch } from 'shared/lib/hook/useAppDispatch/useAppDispatch';
import { useSelector } from 'react-redux';
import { useTranslation } from 'react-i18next';
import { Input } from 'shared/ui/Input/Input';
import { Card } from 'shared/ui/Card/Card';
import { SortOrder } from 'shared/types';
import { fetchArticlesList } from 'pages/ArticlesPage/model/services/fetchArticlesList/fetchArticlesList';
import { useDebounce } from 'shared/lib/hook/useDebounce/useDebounce';
import { TabItem } from 'shared/ui/Tabs/Tabs';
import { ArticleType } from 'entities/Article/model/types/article';
import { ArticleTypeTabs } from 'features/ArticleTypeTabs';
import { fetchArticlesList } from '../../model/services/fetchArticlesList/fetchArticlesList';
import {
ArticleSortField,
ArticleSortSelector,
ArticleView,
} from '../../../../entities/Article';
import { articlesPageActions } from '../../model/slices/articlesPageSlice';
import {
getArticlesPageOrder, getArticlesPageSearch,
getArticlesPageOrder,
getArticlesPageSearch,
getArticlesPageSort,
getArticlesPageType,
getArticlesPageView,
} from '../../model/selectors/articlesPageSelectors';
import cls from './ArticlesPageFilters.module.scss';
Expand All @@ -36,6 +41,7 @@ export const ArticlesPageFilters = memo((props: ArticlesPageFiltersProps) => {
const sort = useSelector(getArticlesPageSort);
const order = useSelector(getArticlesPageOrder);
const search = useSelector(getArticlesPageSearch);
const type = useSelector(getArticlesPageType);

const fetchData = useCallback(() => {
dispatch(fetchArticlesList({ replace: true }));
Expand Down Expand Up @@ -67,6 +73,12 @@ export const ArticlesPageFilters = memo((props: ArticlesPageFiltersProps) => {
debouncedFetchData();
}, [dispatch, debouncedFetchData]);

const onChangeType = useCallback((value: ArticleType) => {
dispatch(articlesPageActions.setType(value));
dispatch(articlesPageActions.setPage(1));
fetchData();
}, [dispatch, fetchData]);

return (
<div className={classNames(cls.ArticlesPageFilters, {}, [className])}>
<div className={cls.sortWrapper}>
Expand All @@ -85,6 +97,11 @@ export const ArticlesPageFilters = memo((props: ArticlesPageFiltersProps) => {
placeholder={t('Search')}
/>
</Card>
<ArticleTypeTabs
value={type}
onChangeType={onChangeType}
className={cls.tabs}
/>
</div>
);
});
7 changes: 7 additions & 0 deletions src/shared/ui/Card/Card.module.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
.Card {
padding: 15px;
border-radius: 12px;
}

.normal {
background: var(--card-bg);
}

.outlined {
border: 1px solid var(--primary-color);
}
Loading

0 comments on commit ac3a03e

Please sign in to comment.