Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#340-sidebar #398

Merged
merged 5 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
13 changes: 10 additions & 3 deletions src/features/CategoryItem/CategoryItem.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
.category-list__item {
display: flex;
align-items: center;
min-height: 45px;
max-width: 270px;
background-color: var.$body-bg;
padding: 10px 40px 10px 14px;
padding: 5px 40px 5px 14px;
margin-bottom: 5px;
border-radius: 5px;
color: var.$body-color;
Expand All @@ -17,7 +15,16 @@
color: var.$theme-primary-color;
}


.category-list__link {
text-decoration: none;
color: inherit;
gap: 5px
}


.category-list__link_active {
text-decoration: none;
gap: 5px;
color: var.$theme-primary-color;
}
22 changes: 18 additions & 4 deletions src/features/CategoryItem/CategoryItem.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,23 @@ export default meta
type Story = StoryObj<typeof meta>
export const Default: Story = {
args: {
name: 'Тестовое имя категории',
slug: '/test',
count: 999,
id: 999
item: {
id: 3434,
name: 'Тестовая категория',
slug: '/test',
total_count: 1,
branches: [
{
id: 3,
name: 'Тестовая подкатегория',
slug: '/test',
products_count: 5,
branches: []
}
],
root: false,
is_prohibited: false,
is_visible_on_main: false
}
}
}
79 changes: 56 additions & 23 deletions src/features/CategoryItem/CategoryItem.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,72 @@
import type { FC } from 'react'
import { useDispatch } from 'react-redux'
import { type FC, useEffect, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { NavLink, useParams } from 'react-router-dom'

import { setCategoryId } from '@/entities/Category/slice/categoryIdSlice'
import { setCategorySlug } from '@/entities/Category/slice/categorySlugSlice'
import styles from '@/features/CategoryItem/CategoryItem.module.scss'
import SideBar from '@/features/SideBar'
import { Routes } from '@/shared/config/routerConfig/routes'
import Link from '@/shared/ui/Link/Link'
import { getCategorySelector } from '@/widgets/CategoryList/selectors/selectors'
import type { BranchesData, MainCategoryInfo } from '@/widgets/CategoryList/types/types'

type Props = {
name: string
slug: string
count: number
id: number
item: MainCategoryInfo
}

/**
* Компонент единицы категории в списке категорий бокового меню
* @param {string} name - название категории;
* @param {string} slug - URL для страницы категориии;
* @param {number} count - количество товаров в категории;
* @param {number} id - id категории;
* @param {MainCategoryInfo} item - главная категория с ветками;
*/
export const CategoryItem: FC<Props> = ({ name, slug, count, id }) => {
export const CategoryItem: FC<Props> = ({ item }) => {
const dispatch = useDispatch()

const { slug } = useParams()
const getMainCategories = useSelector(getCategorySelector)

const [itemActive, setItemActive] = useState<MainCategoryInfo | BranchesData>()
const [branch, setBranch] = useState<MainCategoryInfo | BranchesData>()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Давай эти два стейта и useEffect вынесем в кастомный хук, откуда будем получать эти параметры.
Положить его можно в папку с этим же компонентом в models


useEffect(() => {
if (getMainCategories.find(el => el.slug === slug)) {
setItemActive(getMainCategories.find(el => el.slug === slug))
} else if (item.branches.find(el => el.slug === slug)) {
setItemActive(item.branches.find(el => el.slug === slug))
setBranch(getMainCategories.find(el => el.branches.find(el => el.name === itemActive?.name)))
}
}, [itemActive])

return (
<li className={styles['category-list__item']}>
<Link
to={`${Routes.CATEGORIES}/${slug}`}
className={styles['category-list__link']}
onClick={() => {
dispatch(setCategoryId(id))
dispatch(setCategorySlug(slug))
}}>
{name} ({count})
</Link>
</li>
<SideBar
key={item.id}
isVisible={true}
title={`${item.name} (${item.total_count})`}
onClick={() => {
dispatch(setCategoryId(item.id))
dispatch(setCategorySlug(item.slug))
}}
to={`${Routes.CATEGORIES}/${item.slug}`}
activeElement={itemActive}
branch={branch}
itemName={item.name}>
<ul role="list">
{item.branches.map(el => (
<li key={el.id} className={styles['category-list__item']}>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Может добавим проверку, что в item есть branches?

<NavLink
role="link"
to={`${Routes.CATEGORIES}/${el.slug}`}
className={({ isActive }) =>
isActive ? styles['category-list__link_active'] : styles['category-list__link']
}
onClick={() => {
dispatch(setCategoryId(el.id))
dispatch(setCategorySlug(el.slug))
}}>
{el.name} ({el.products_count})
</NavLink>
</li>
))}
</ul>
</SideBar>
)
}
56 changes: 46 additions & 10 deletions src/features/SideBar/ui/SideBar.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { KeyboardEvent, KeyboardEventHandler, ReactElement, useState, type FC } from 'react'
import { KeyboardEvent, KeyboardEventHandler, ReactElement, useState, type FC, useEffect } from 'react'

import ArrowIcon from '@/assets/images/sideBarMenu/IconArrowDown.svg'
import Link from '@/shared/ui/Link/Link'
import Paragraph from '@/shared/ui/Paragraph/Paragraph'
import { BranchesData, MainCategoryInfo } from '@/widgets/CategoryList/types/types'

import styles from './SideBar.module.scss'

Expand All @@ -11,6 +13,10 @@ export interface ISideBar {
onClick?: () => void
onKeyUp?: KeyboardEventHandler<HTMLLIElement>
children?: ReactElement | JSX.Element | JSX.Element[]
to?: string | undefined
activeElement?: MainCategoryInfo | BranchesData
branch?: MainCategoryInfo | BranchesData
itemName?: string
}

/**
Expand All @@ -20,11 +26,36 @@ export interface ISideBar {
* @param {function} onClick - функция выхода из профиля handleLogOut;
* @param {function} onKeyUp - функция выхода из профиля handleLogOut при нажатии клавиши Enter;
* @param {JSX.Element} children - контент;
* Далее, для сайдбара на странице категори;
* @param {string} to - если есть ссылка для item верхнего уровня, передает путь
* @param {MainCategoryInfo | BranchesData} activeElement - item верхнего уровня, на который кликнули
Copy link
Collaborator

Choose a reason for hiding this comment

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

Эти параметры я бы передавал объектом, так же еще я бы добавил флаг - раскрывающийся или нет это sidebar, чтобы было сразу понятно, как мы его используем

* @param {MainCategoryInfo | BranchesData} branch - item из children, на который кликнули
* @param {string} itemName - название item, на который кликнули
*/

const SideBar: FC<ISideBar> = ({ title, isVisible, onClick, onKeyUp, children }) => {
const SideBar: FC<ISideBar> = ({
title,
isVisible,
onClick,
onKeyUp,
children,
to,
activeElement,
branch,
itemName
}) => {
const [isActive, setIsActive] = useState(false)

useEffect(() => {
if (activeElement?.name === itemName && activeElement !== undefined) {
setIsActive(true)
} else if (branch) {
setIsActive(true)
} else {
setIsActive(false)
}
}, [activeElement?.slug, branch])

const handleClick = () => {
setIsActive(!isActive)
}
Expand All @@ -38,17 +69,22 @@ const SideBar: FC<ISideBar> = ({ title, isVisible, onClick, onKeyUp, children })
}

return (
<li
tabIndex={0}
role="button"
onKeyUp={onKeyUp}
onKeyDown={handleKeyDown}
onClick={onClick}
className={styles.sideBar}>
<li tabIndex={0} role="button" onKeyUp={onKeyUp} onKeyDown={handleKeyDown} className={styles.sideBar}>
<div onClick={handleClick} className={styles.sideBar__header}>
<Paragraph className={styles.sideBar__headerText}>{title}</Paragraph>
{to ? (
<Link to={to}>
<Paragraph className={styles.sideBar__headerText} onClick={onClick}>
{title}
</Paragraph>
</Link>
) : (
<Paragraph className={styles.sideBar__headerText} onClick={onClick}>
{title}
</Paragraph>
)}
{isVisible && (
<ArrowIcon
onClick={handleClick}
className={`${styles.sideBar__headerArrow} ${isActive && styles.sideBar__headerArrow_active}`}
/>
)}
Expand Down
2 changes: 2 additions & 0 deletions src/widgets/CategoryList/CategoryList.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ https://github.com/Studio-Yandex-Practicum/maxboom_frontend/issues/61 */
.category-list__items {
max-height: calc(100% - 50px);
overflow-y: auto;
gap: 10px;
display: grid;
}
24 changes: 2 additions & 22 deletions src/widgets/CategoryList/CategoryList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { getLoading } from '@/pages/ProductsPage/selectors/selectors'
import { NUMBER_OF_CATEGORY_LINES } from '@/shared/constants/constants'
import { useAppDispatch } from '@/shared/libs/hooks/store'
import Heading, { HeadingType } from '@/shared/ui/Heading/Heading'
import { getCategoryBranchesSelector, getCategorySelector } from '@/widgets/CategoryList/selectors/selectors'
import { getCategorySelector } from '@/widgets/CategoryList/selectors/selectors'
import { getCategoryBranches } from '@/widgets/CategoryList/services/getCategoryBranches'
import { getCategories } from '@/widgets/CategoryList/services/getCatergories'

Expand All @@ -21,7 +21,6 @@ import styles from './CategoryList.module.scss'
*/
export const CategoryList: FC = () => {
const dispatch = useAppDispatch()
const categoryBranches = useSelector(getCategoryBranchesSelector)
const getMainCategories = useSelector(getCategorySelector)
const categorySlug = useSelector(selectCategorySlug)

Expand All @@ -44,26 +43,7 @@ export const CategoryList: FC = () => {
? Array(NUMBER_OF_CATEGORY_LINES)
.fill(0)
.map((_, i) => <CategoryItemSkeleton key={i} />)
: categoryBranches.branches?.length > 0
? categoryBranches.branches.map(item => (
<CategoryItem
key={item.id}
id={item.id}
name={item.name}
slug={item.slug}
count={item.products_count}
/>
))
: getMainCategories.map(item => (
<CategoryItem
key={item.id}
id={item.id}
name={item.name}
slug={item.slug}
// Поля count в списке категорий верхнего уровня на бэке нет, если мы его оставляем, то нужно будет запросить вывод количества товаров
count={0}
/>
))}
: getMainCategories.map(item => <CategoryItem item={item} key={item.id} />)}
</ul>
</div>
)
Expand Down
1 change: 1 addition & 0 deletions src/widgets/CategoryList/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export interface IMainCategorySchema {
}

export interface MainCategoryInfo {
total_count?: number
id: number
name: string
slug: string
Expand Down
Loading