-
Notifications
You must be signed in to change notification settings - Fork 1
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
#305-skeletons #329
#305-skeletons #329
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,11 +10,13 @@ import { Pagination } from '@/components/Pagination/Pagination' | |
import WrapperForMainContent from '@/components/WrapperForMainContent/WrapperForMainContent' | ||
import { selectCategorySlug } from '@/entities/Category/selectors/categorySelectors' | ||
import { TOTAL_PAGES } from '@/mockData/productsPageOptions' | ||
import { getProductsOfCategorySelector } from '@/pages/ProductsPage/selectors/selectors' | ||
import { getLoading, getProductsOfCategorySelector } from '@/pages/ProductsPage/selectors/selectors' | ||
import { getProducts } from '@/pages/ProductsPage/services/getProducts' | ||
import { ITEMS_PER_PAGE_OPTION, SORT_OPTION } from '@/shared/constants/constants' | ||
import { useAppDispatch } from '@/shared/libs/hooks/store' | ||
import { ECardView } from '@/shared/model/types/common' | ||
import { PageControlsSkeletons } from '@/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons' | ||
import { ProductSkeleton } from '@/shared/ui/Skeletons/ProductSkeleton/ProductSkeleton' | ||
import { CategoryList } from '@/widgets/CategoryList/CategoryList' | ||
import { ProductsList } from '@/widgets/ProductsList/ProductsList' | ||
|
||
|
@@ -46,6 +48,8 @@ export const ProductsPage = () => { | |
const selectQuantityFilter = useSelector(selectFilterQuantity) | ||
const filterQuantity = selectQuantityFilter ? `&limit=${selectQuantityFilter.value}` : '' | ||
|
||
const isLoading = useSelector(getLoading) | ||
|
||
const handleSortChange: React.ChangeEventHandler<HTMLSelectElement> = event => { | ||
const selectedOption = event.target.value | ||
const setCategoryFilters = SORT_OPTION.find(item => item.name === selectedOption) | ||
|
@@ -88,7 +92,16 @@ export const ProductsPage = () => { | |
<CategoryList /> | ||
<div className={styles['content-main']}> | ||
<section className={styles['content-products']}> | ||
{categoriesProducts.results.length > 0 ? ( | ||
{isLoading ? ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. вот так же делаем с PageDescriptionSkeleton |
||
<> | ||
<PageControlsSkeletons /> | ||
{Array(15) | ||
.fill(0) | ||
.map(sk => ( | ||
<ProductSkeleton key={sk} /> | ||
))} | ||
</> | ||
) : categoriesProducts.results.length > 0 ? ( | ||
<> | ||
<PageControls | ||
cardView={cardView} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,10 @@ | ||
import { StateSchema } from '@/app/providers/StoreProvider' | ||
import { RootState } from '@/app/providers/StoreProvider/config/store' | ||
|
||
export const getProductsOfCategorySelector = (state: StateSchema) => { | ||
return state.categoryProduct.productsData | ||
} | ||
|
||
export const getLoading = (state: RootState) => { | ||
return state.categoryProduct.isLoading | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
@use '../../../styles/utils/variables' as var; | ||
|
||
.sk-page-controls { | ||
width: 100%; | ||
display: flex; | ||
justify-content: space-between; | ||
|
||
&__dropdowns { | ||
display: flex; | ||
gap: 12px; | ||
} | ||
|
||
&__dropdown { | ||
width: 150px; | ||
height: 36px; | ||
} | ||
|
||
&__cards-controls { | ||
display: flex; | ||
gap: 10px; | ||
} | ||
|
||
&__cards-control { | ||
width: 36px; | ||
height: 36px; | ||
border-radius: 6px; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { Meta, StoryObj } from '@storybook/react' | ||
import { type FC } from 'react' | ||
|
||
import { PageControlsSkeletons } from '@/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons' | ||
|
||
const StorybookWrapper: FC = () => { | ||
return ( | ||
<div> | ||
<PageControlsSkeletons /> | ||
</div> | ||
) | ||
} | ||
|
||
const meta = { | ||
title: 'shared/PageControlsSkeletons', | ||
component: StorybookWrapper, | ||
tags: ['autodocs'] | ||
} satisfies Meta<typeof StorybookWrapper> | ||
|
||
export default meta | ||
type Story = StoryObj<typeof meta> | ||
|
||
export const Default: Story = {} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. это храним не в shared, а в компоненте PafeControlsSkeleton, например в папке ui. Потому что skeleton относится именно к своему компоненту |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { type FC } from 'react' | ||
import Skeleton from 'react-loading-skeleton' | ||
import 'react-loading-skeleton/dist/skeleton.css' | ||
|
||
import styles from './PageControlsSkeletons.module.scss' | ||
|
||
export const PageControlsSkeletons: FC = () => { | ||
return ( | ||
<div className={styles['sk-page-controls']}> | ||
<div className={styles['sk-page-controls__dropdowns']}> | ||
<Skeleton className={styles['sk-page-controls__dropdown']} inline={true} /> | ||
<Skeleton className={styles['sk-page-controls__dropdown']} inline={true} /> | ||
</div> | ||
<ul className={styles['sk-page-controls__cards-controls']}> | ||
<Skeleton className={styles['sk-page-controls__cards-control']} inline={true} /> | ||
<Skeleton className={styles['sk-page-controls__cards-control']} inline={true} /> | ||
<Skeleton className={styles['sk-page-controls__cards-control']} inline={true} /> | ||
</ul> | ||
</div> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
@use '../../../styles/utils/variables' as var; | ||
|
||
.sk-product-item { | ||
padding: 20px; | ||
background-color: var.$white; | ||
border-radius: 10px; | ||
|
||
|
||
&_type_grid { | ||
flex-direction: column; | ||
width: 292px; | ||
} | ||
|
||
&__header { | ||
display: flex; | ||
justify-content: end; | ||
} | ||
|
||
&__buttons { | ||
display: flex; | ||
width: 50px; | ||
height: 40px; | ||
} | ||
|
||
&__carousel { | ||
height: 300px; | ||
} | ||
|
||
|
||
&__indicator { | ||
margin-top: 10px; | ||
margin-bottom: 15px; | ||
} | ||
|
||
&__dot { | ||
width: 100%; | ||
height: 2px; | ||
background-color: #ebebeb; | ||
} | ||
|
||
&__description-container { | ||
display: flex; | ||
flex-direction: column; | ||
gap: 10px; | ||
} | ||
|
||
&__info { | ||
height: 33px | ||
} | ||
|
||
&__price { | ||
font-size: 18px; | ||
font-weight: 900; | ||
width: 55px; | ||
height: 25px; | ||
margin-top: 10px; | ||
}} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { Meta, StoryObj } from '@storybook/react' | ||
import { type FC } from 'react' | ||
|
||
import { ProductSkeleton } from '@/shared/ui/Skeletons/ProductSkeleton/ProductSkeleton' | ||
|
||
const StorybookWrapper: FC = () => { | ||
return ( | ||
<div> | ||
<ProductSkeleton /> | ||
</div> | ||
) | ||
} | ||
|
||
const meta = { | ||
title: 'shared/ProductSkeleton', | ||
component: StorybookWrapper, | ||
tags: ['autodocs'] | ||
} satisfies Meta<typeof StorybookWrapper> | ||
|
||
export default meta | ||
type Story = StoryObj<typeof meta> | ||
|
||
export const Default: Story = {} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. переносим к своему компоненту |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { type FC } from 'react' | ||
import Skeleton from 'react-loading-skeleton' | ||
import 'react-loading-skeleton/dist/skeleton.css' | ||
|
||
import styles from './ProductSkeleton.module.scss' | ||
|
||
export const ProductSkeleton: FC = () => { | ||
return ( | ||
<div className={`${styles['sk-product-item']} ${styles['sk-product-item_type_grid']}`}> | ||
<div className={styles['sk-product-item__header']}> | ||
<Skeleton className={styles['sk-product-item__buttons']} /> | ||
</div> | ||
<div> | ||
<Skeleton className={styles['sk-product-item__carousel']} /> | ||
<div className={styles['sk-product-item__indicator']}> | ||
<div className={styles['sk-product-item__dot']}></div> | ||
</div> | ||
</div> | ||
<div> | ||
<div className={styles['sk-product-item__description-container']}> | ||
<Skeleton /> | ||
<Skeleton className={styles['sk-product-card__info']} /> | ||
<div> | ||
<Skeleton className={styles['sk-product-item__price']} /> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,11 @@ | ||
import { FC, useEffect } from 'react' | ||
import { type FC, useEffect } from 'react' | ||
import Skeleton from 'react-loading-skeleton' | ||
import { useSelector } from 'react-redux' | ||
import { useParams } from 'react-router-dom' | ||
|
||
import { selectCategorySlug } from '@/entities/Category/selectors/categorySelectors' | ||
import { CategoryItem } from '@/features/CategoryItem/CategoryItem' | ||
import { getLoading } from '@/pages/ProductsPage/selectors/selectors' | ||
import { useAppDispatch } from '@/shared/libs/hooks/store' | ||
import Heading, { HeadingType } from '@/shared/ui/Heading/Heading' | ||
import { getCategoryBranchesSelector, getCategorySelector } from '@/widgets/CategoryList/selectors/selectors' | ||
|
@@ -24,22 +26,24 @@ export const CategoryList: FC = () => { | |
|
||
const { slug } = useParams() | ||
|
||
useEffect(() => { | ||
dispatch(getCategoryBranches(slug)) | ||
}, []) | ||
const isLoading = useSelector(getLoading) | ||
|
||
useEffect(() => { | ||
dispatch(getCategoryBranches(categorySlug)) | ||
dispatch(getCategoryBranches(slug)) | ||
dispatch(getCategories()) | ||
}, [categorySlug]) | ||
}, [categorySlug, slug]) | ||
|
||
return ( | ||
<div className={styles['category-list']}> | ||
<Heading type={HeadingType.NORMAL} className={styles['category-list__title']}> | ||
Категории | ||
</Heading> | ||
<ul className={styles['category-list__items']}> | ||
{categoryBranches.branches?.length > 0 | ||
{isLoading | ||
? Array(15) | ||
.fill(0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 15 - в константы |
||
.map(sk => <Skeleton className={styles['sk-category-list__item']} inline={true} key={sk} />) | ||
: categoryBranches.branches?.length > 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. так не делаем, здесь должен быть компонент CategoryItemSkeleton, его уже здесь рендерим |
||
? categoryBranches.branches.map(item => ( | ||
<CategoryItem | ||
key={item.id} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
давай сделаем как с остальными скелетонами
PageDescription - не нужно знать о загрузке и тд, по сути мы его можем переиспользовать в других компонентах, где даже может не быть обращение к серверу.
Тоесть, здесь тоже делаем компонент PageDescriptionSkeleton и используем его в зависимости от флага загрузки