diff --git a/src/app/providers/StoreProvider/config/StateSchema.ts b/src/app/providers/StoreProvider/config/StateSchema.ts index c0f84a25..a6a55ed1 100644 --- a/src/app/providers/StoreProvider/config/StateSchema.ts +++ b/src/app/providers/StoreProvider/config/StateSchema.ts @@ -12,12 +12,12 @@ import type { TProductSchema } from '@/pages/ProductPage/model/types/productType import type { CategoryListSchema } from '@/widgets/CategoryGrid/model/types/types' import type { ICategoryProductsSchema } from '@/pages/ProductsPage/types/types' import type { ICategorySchema, IMainCategorySchema } from '@/widgets/CategoryList/types/types' -import type { ICategoryFiltersSchema } from '@/components/Dropdown/types/types' +import type { ICategoryFiltersSchema } from '@/shared/ui/Dropdown/types/types' import type { IFeedbackFormSchema } from '@/widgets/FeedbackForm/model/scheme/feedbackFormSliceSchema' import type { ICartEntitySchema } from '@/entities/CartEntity/model/types/types' import type { IAboutUsSchema } from '@/pages/AboutUsPage/model/types/types' import type { IFeedbackSchema } from '@/features/Reviews/model/types/types' -import type { TNumberOfPageSchema } from '@/components/Pagination/types/types' +import type { TNumberOfPageSchema } from '@/widgets/Pagination/types/types' export interface StateSchema { aboutUs: IAboutUsSchema diff --git a/src/app/providers/StoreProvider/config/store.ts b/src/app/providers/StoreProvider/config/store.ts index 88d5aaaf..665f26b4 100644 --- a/src/app/providers/StoreProvider/config/store.ts +++ b/src/app/providers/StoreProvider/config/store.ts @@ -17,12 +17,12 @@ import { categoryIdSliceReducer } from '@/entities/Category/slice/categoryIdSlic import { categorySlugSliceReducer } from '@/entities/Category/slice/categorySlugSlice' import { categoryBranchesReducer } from '@/widgets/CategoryList/slice/pageCategoryBranchesSlice' import { getCategoriesReducer } from '@/widgets/CategoryList/slice/pageCategoriesSlice' -import { categoryFiltersSliceReducer } from '@/components/Dropdown/slice/filtersSlice' +import { categoryFiltersSliceReducer } from '@/shared/ui/Dropdown/slice/filtersSlice' import { feedbackFormReducer } from '@/widgets/FeedbackForm/model/slice/feedbackFormSlice' import { aboutUsReducer } from '@/pages/AboutUsPage/model/slice/aboutUsSlice' import { cartEntityReducer } from '@/entities/CartEntity/model/slice/cartEntitySlice' import { feedbacksReducer } from '@/features/Reviews/model/slice/feedbacksSlice' -import { paginationSliceReducer } from '@/components/Pagination/slice/paginationSlice' +import { paginationSliceReducer } from '@/widgets/Pagination/slice/paginationSlice' export type RootState = StateSchema diff --git a/src/app/router/AppRouter/ui/AppRouter.tsx b/src/app/router/AppRouter/ui/AppRouter.tsx index 74900a89..2169ffb2 100644 --- a/src/app/router/AppRouter/ui/AppRouter.tsx +++ b/src/app/router/AppRouter/ui/AppRouter.tsx @@ -17,11 +17,14 @@ import HelpPage from '@/pages/HelpPage/HelpPage' import LoginPage from '@/pages/LoginPage/LoginPage' import { LogoutPage } from '@/pages/LogoutPage/LogoutPage' import MainPage from '@/pages/MainPage/MainPage' +import { PrivacyPage } from '@/pages/PrivacyPage/PrivacyPage' import { ProductPage } from '@/pages/ProductPage/ProductPage' import { ProductsPage } from '@/pages/ProductsPage/ProductsPage' +import { ReviewsPage } from '@/pages/ReviewsPage/ReviewsPage' import RootPage from '@/pages/RootPage/RootPage' import SearchResultsPage from '@/pages/SearchResultsPage/SearchResultsPage' import ShopNewsPage from '@/pages/ShopNewsPage/ShopNewsPage' +import { TermsPage } from '@/pages/TermsPage/TermsPage' import VouchersPage from '@/pages/VouchersPage/VouchersPage' import { Routes } from '@/shared/config/routerConfig/routes' @@ -83,7 +86,7 @@ export const AppRouter = createBrowserRouter([ }, { path: Routes.PRIVACY, - element: // временная заглушка нужна страница с политикой безопасности + element: }, { path: Routes.PRODUCTS, @@ -94,9 +97,13 @@ export const AppRouter = createBrowserRouter([ element: }, { - path: Routes.REVIEWS + '/:index', + path: Routes.FEEDBACKS + '/:index', element: }, + { + path: Routes.REVIEWS, + element: + }, { path: Routes.SEARCH, element: @@ -107,7 +114,7 @@ export const AppRouter = createBrowserRouter([ }, { path: Routes.TERMS, - element: // временная заглушка нужна страница с условиями соглашения + element: }, { path: Routes.ADD_RETURN, diff --git a/src/assets/icons/WB.svg b/src/assets/icons/WB.svg new file mode 100644 index 00000000..250c42fc --- /dev/null +++ b/src/assets/icons/WB.svg @@ -0,0 +1,369 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/blogMainItem/img-article-02-1500x1000.webp.svg b/src/assets/images/blogMainItem/img-article-02-1500x1000.webp.svg deleted file mode 100644 index 57246677..00000000 --- a/src/assets/images/blogMainItem/img-article-02-1500x1000.webp.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/components/BlogCategories/BlogCategories.tsx b/src/components/BlogCategories/BlogCategories.tsx deleted file mode 100644 index 1828388d..00000000 --- a/src/components/BlogCategories/BlogCategories.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { FC, useMemo } from 'react' - -import type { PropsCategories } from '@/models/PropsBlog' -import Heading, { HeadingType } from '@/shared/ui/Heading/Heading' - -import styles from './blog-categories.module.scss' - -const BlogCategories: FC = props => { - const { cards, filterItems } = props - - const cat = useMemo( - () => - cards.map(item => { - return item.category - }), - [cards] - ) - - const result: { - key?: string - count: number - }[] = [] - // Create a unique list of items to loop over - // Add each item to the result list - ;[...new Set(cat)].forEach(item => - useMemo( - () => - result.push({ - key: item, - // Get the count of items of the current type - count: cat.filter(i => i == item).length - }), - [result] - ) - ) - - const uniqueCats = useMemo( - () => - result.map(item => { - return ( - - ) - }), - [[...new Set(cat)]] - ) - - return ( -
-
- Категории -
    {uniqueCats}
-
-
- ) -} - -export default BlogCategories diff --git a/src/components/BlogCategories/blog-categories.module.scss b/src/components/BlogCategories/blog-categories.module.scss deleted file mode 100644 index 47b03eb1..00000000 --- a/src/components/BlogCategories/blog-categories.module.scss +++ /dev/null @@ -1,30 +0,0 @@ -@use '@/app/styles/index' as var; - -.cats { - display: flex; - max-width: 340px; - padding: 40px 30px 65px; - align-items: flex-start; - border-radius: 10px; - background: #fff; - - &__items { - margin-top: 25px; - max-width: 280px; - display: flex; - flex-flow: column wrap; - } - - &__item { - display: flex; - width: 280px; - height: 45px; - padding: 13.5px 15px; - align-items: center; - border-radius: 5px; - margin-bottom: 5px; - margin-right: 5px; - background-color: #f7f7fb; - justify-content: space-between; - } -} diff --git a/src/components/BlogItemForContainer/BlogItemForContainer.tsx b/src/components/BlogItemForContainer/BlogItemForContainer.tsx deleted file mode 100644 index 4bd1ef8e..00000000 --- a/src/components/BlogItemForContainer/BlogItemForContainer.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { FC, useMemo } from 'react' - -import CommentIcon from '@/assets/images/blogMainItem/icon-comments.svg' -import ViewIcon from '@/assets/images/blogMainItem/icon-views.svg' -import type { TBlogItem } from '@/models/BlogItemModel' -import { TEXT_PROMO } from '@/shared/constants/constants' -import { fromSS } from '@/shared/constants/constants' -import Link from '@/shared/ui/Link/Link' - -import styles from './blog-item-for-container.module.scss' - -export type Props = { - card: TBlogItem -} - -const BlogItemForContainer: FC = props => { - const { card } = props - const tags = useMemo( - () => - card.tags.map(item => { - return ( -

- {item} -

- ) - }), - [] - ) - - return ( - - {card.alt} -
{tags}
-

{card.title || ''}

-
-

- {fromSS} -

-

- {card.comments.length} -

-
- {card.date || ''} - {card.promo ? {TEXT_PROMO} : null} - - ) -} - -export default BlogItemForContainer diff --git a/src/components/BlogItemForContainer/blog-item-for-container.module.scss b/src/components/BlogItemForContainer/blog-item-for-container.module.scss deleted file mode 100644 index 7f488eb6..00000000 --- a/src/components/BlogItemForContainer/blog-item-for-container.module.scss +++ /dev/null @@ -1,103 +0,0 @@ -@use '@/app/styles/index' as var; - -.card { - position: relative; - transition: transform 0.3s ease-in-out; - display: flex; - flex-direction: column; - justify-content: space-between; - gap: 15px; - padding-bottom: 50px; - - &__info { - position: absolute; - bottom: 160px; - left: 20px; - margin: 0; - display: flex; - align-items: center; - } - - &__icons { - margin-right: 20px; - color: #fff; - font-size: 15px; - font-style: normal; - font-weight: 500; - line-height: 24px; /* 160% */ - display: flex; - align-items: center; - - &:last-child { - margin: 0; - } - } - - &__icon { - border-radius: 6px; - transition: transform 0.3s ease-in-out; - scroll-snap-align: start; - margin-right: 7px; - } - - &__tags { - position: absolute; - top: 30px; - left: 30px; - display: flex; - } - - &__tag { - display: flex; - height: 35px; - padding: 0 12px; - align-items: center; - background-color: #f7f7fb33; - color: #fff; - font-size: 14px; - font-style: normal; - font-weight: 400; - line-height: 16.8px; - border-radius: 5px; - margin-right: 10px; - } - - &__im { - width: 340px; - height: 462px; - } - - &:hover { - transform: scale(1.1, 1.05); - transition: transform 0.3s ease-in-out; - } - - h3 { - width: 95%; - font-size: #{'min(max(14px, 1.2vw), 16px)'}; - line-height: 150%; - font-weight: 500; - } - - &:hover h3 { - color: var.$link-color; - } - - span { - color: var.$body-color-light-grey; - } - - .promo { - display: inline-block; - position: absolute; - top: 15px; - left: 15px; - background: var.$promo-color; - border-radius: 5px; - padding: 5px 10px; - color: var.$white; - font-size: 15px; - line-height: 120%; - font-weight: 500; - } -} diff --git a/src/components/BlogMain/BlogMain.tsx b/src/components/BlogMain/BlogMain.tsx deleted file mode 100644 index 4dc261f4..00000000 --- a/src/components/BlogMain/BlogMain.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { FC, useState } from 'react' - -import type { PropsBlog } from '@/models/PropsBlog' -import Heading from '@/shared/ui/Heading/Heading' -import Subheading from '@/shared/ui/Subheading/Subheading' - -import BlogCategories from '../BlogCategories/BlogCategories' -import BlogItemForContainer from '../BlogItemForContainer/BlogItemForContainer' -import BlogMainItem from '../BlogMainItem/BlogMainItem' -import BlogTags from '../BlogTags/BlogTags' -import { Pagination } from '../Pagination/Pagination' -import WrapperForMainContent from '../WrapperForMainContent/WrapperForMainContent' - -import styles from './blog-main.module.scss' - -const BlogMain: FC = props => { - const { cards } = props - const [items, setItems] = useState(cards) - const [itemNumber, setItemNumber] = useState(9) - const [currentPage, setCurrentPage] = useState(1) - const TOTAL_PAGES: number = Math.ceil(items.length / itemNumber) - const filterCategories = (curcat?: string) => { - const newItems = cards.filter(newVal => { - return newVal.category === curcat - // comparing category for displaying data - }) - setItems(newItems) - } - - const filterTags = (curcat: string) => { - const newItems = cards.filter(newVal => { - return newVal.tags.includes(curcat) - // comparing category for displaying data - }) - setItems(newItems) - } - - const handlePageChange = (pageNumber: number) => { - // Handle page change logic here - setCurrentPage(pageNumber) - } - - const handleShowMore = () => { - // ... - if (currentPage < TOTAL_PAGES) setCurrentPage(currentPage + 1) - setItemNumber(9) - } - - return ( - -
- Блог - Главная/Блог -
-
-
- - -
-
- -
    - {items - .slice(currentPage == 1 ? 0 : itemNumber * (currentPage - 1), itemNumber * currentPage) - .map(item => ( - - ))} -
-
-
- -
- ) -} - -export default BlogMain diff --git a/src/components/BlogMain/blog-main.module.scss b/src/components/BlogMain/blog-main.module.scss deleted file mode 100644 index 5e148b08..00000000 --- a/src/components/BlogMain/blog-main.module.scss +++ /dev/null @@ -1,80 +0,0 @@ -@use '@/app/styles/index' as var; - -.blog { - align-self: flex-start; - - &__title { - text-align: left; - margin: 24px 0 0; - padding: 0; - } - - &__path { - text-align: left; - margin: 0 0 30px; - padding: 0; - } - - &__filters { - display: flex; - max-width: 340px; - flex-direction: column; - } - - &__wrapper { - display: flex; - max-width: 100%; - gap: 10px; - } -} - -.wrapper { - display: flex; - flex-direction: column; - gap: 50px; - max-width: 100%; - box-sizing: border-box; - - h2 { - font-size: #{'min(max(18px, 1.6vw), 20px)'}; - line-height: 115%; - font-weight: 500; - } - - article { - display: flex; - justify-content: space-between; - align-items: flex-end; - padding: 0 10px; - max-width: 100%; - } - - .link { - font-size: 15px; - line-height: 120%; - font-weight: 500; - color: var.$link-color; - } - - ul { - max-width: 1080px; - display: flex; - flex-wrap: wrap; - justify-content: center; - cursor: grab; - - &::-webkit-scrollbar { - height: 3px; - } - - &::-webkit-scrollbar-thumb { - background: var.$theme-primary-color; - cursor: grab; - } - - &::-webkit-scrollbar-track { - margin-left: 10px; - margin-right: 10px; - } - } -} diff --git a/src/components/BlogMainItem/BlogMainItem.tsx b/src/components/BlogMainItem/BlogMainItem.tsx deleted file mode 100644 index 5c41b00f..00000000 --- a/src/components/BlogMainItem/BlogMainItem.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { useEffect, useMemo } from 'react' - -import CommentIcon from '@/assets/images/blogMainItem/icon-comments.svg' -import DotIcon from '@/assets/images/blogMainItem/icon-dot.svg' -import ViewIcon from '@/assets/images/blogMainItem/icon-views.svg' -import { blogMainItemData } from '@/mockData/blogMainItemData' -import { fromSS } from '@/shared/constants/constants' -import Link from '@/shared/ui/Link/Link' - -import styles from './blog-main-item.module.scss' - -function BlogMainItem() { - const mainItem = blogMainItemData - const tags = useMemo( - () => - blogMainItemData.tags.map(item => { - return ( -

- {item} -

- ) - }), - [] - ) - - useEffect(() => { - const fromSS = sessionStorage.getItem('homeview') - if (!fromSS) { - const timer = setTimeout(() => { - sessionStorage.setItem('homeview', '1') - }, 10000) - - return () => clearTimeout(timer) - } - }, []) - - return ( - - {mainItem.alt} -
{tags}
-

{mainItem.title || ''}

-
-

- {fromSS} -

-

- {mainItem.comments.length} -

-

- - {mainItem.date || ''} -

-
- - ) -} - -export default BlogMainItem diff --git a/src/components/BlogMainItem/blog-main-item.module.scss b/src/components/BlogMainItem/blog-main-item.module.scss deleted file mode 100644 index c99f9276..00000000 --- a/src/components/BlogMainItem/blog-main-item.module.scss +++ /dev/null @@ -1,110 +0,0 @@ -@use '@/app/styles/index' as var; - -.main { - position: relative; - transition: transform 0.3s ease-in-out; - display: flex; - flex-direction: column; - justify-content: space-between; - gap: 25px; - max-width: 1060px; - padding-left: 20px; - padding-right: 10px; - - &:hover { - transform: scale(1.1, 1.05); - transition: transform 0.3s ease-in-out; - } - - &__tags { - position: absolute; - top: 30px; - left: 30px; - display: flex; - } - - &__tag { - display: flex; - height: 35px; - padding: 0 12px; - align-items: center; - background-color: #f7f7fb33; - color: #fff; - font-size: 14px; - font-style: normal; - font-weight: 400; - line-height: 16.8px; - border-radius: 5px; - margin-right: 10px; - } - - img { - border-radius: 6px; - transition: transform 0.3s ease-in-out; - scroll-snap-align: start; - } - - h3 { - max-width: 373px; - position: absolute; - bottom: 38px; - left: 30px; - margin: 0; - color: white; - font-size: 20px; - font-style: normal; - font-weight: 500; - line-height: 30px; /* 150% */ - } - - &:hover h3 { - color: var.$link-color; - } - - span { - color: var.$body-color-light-grey; - margin-left: 18px; - } - - .main__info { - position: absolute; - bottom: 30px; - right: 30px; - margin: 0; - display: flex; - align-items: center; - } - - .main__icons { - margin-right: 20px; - color: #fff; - font-size: 15px; - font-style: normal; - font-weight: 500; - line-height: 24px; /* 160% */ - display: flex; - align-items: center; - - &:last-child { - margin: 0; - } - } - - .main__icon { - margin-right: 7px; - } - - .promo { - display: inline-block; - position: absolute; - top: 15px; - left: 15px; - background: var.$promo-color; - border-radius: 5px; - padding: 5px 10px; - color: var.$white; - font-size: 15px; - line-height: 120%; - font-weight: 500; - } -} diff --git a/src/components/BlogTags/BlogTags.tsx b/src/components/BlogTags/BlogTags.tsx deleted file mode 100644 index a5b8e422..00000000 --- a/src/components/BlogTags/BlogTags.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { FC, useMemo } from 'react' - -import type { PropsTags } from '@/models/PropsBlog' - -import styles from './blog-tags.module.scss' - -const BlogTags: FC = props => { - const { cards, filterItems } = props - const tags = useMemo( - () => - cards.map(item => { - return item.tags - }), - [cards] - ) - - const tagsAll = useMemo( - () => - tags.reduce(function (arr, e) { - return arr.concat(e) - }), - [tags] - ) - - const arrayOfTags = Array.from(new Set(tagsAll)) - const uniqueTags = useMemo( - () => - arrayOfTags.map(item => { - return ( - - ) - }), - arrayOfTags - ) - - return ( -
-
-

Тэги

-
    {uniqueTags}
-
-
- ) -} - -export default BlogTags diff --git a/src/components/BlogTags/blog-tags.module.scss b/src/components/BlogTags/blog-tags.module.scss deleted file mode 100644 index e9340a57..00000000 --- a/src/components/BlogTags/blog-tags.module.scss +++ /dev/null @@ -1,42 +0,0 @@ -@use '@/app/styles/index' as var; - -.tags { - display: flex; - max-width: 340px; - padding: 0 30px 25px; - align-items: flex-start; - border-radius: 10px; - background: #fff; - - &__title { - color: #343434; - font-size: 16px; - font-style: normal; - font-weight: 400; - line-height: 19.2px; - } - - &__items { - margin-top: 25px; - display: flex; - max-width: 280px; - flex-wrap: wrap; - } - - &__item { - color: #343434; - font-size: 14px; - font-style: normal; - font-weight: 400; - line-height: 16.8px; /* 120% */ - background-color: #f7f7fb; - display: flex; - height: 35px; - padding: 0 12px; - justify-content: center; - align-items: center; - border-radius: 5px; - margin-bottom: 5px; - margin-right: 5px; - } -} diff --git a/src/components/PageControls/PageControlsSkeletons/PageControlsSkeletons.module.scss b/src/components/PageControls/PageControlsSkeletons/PageControlsSkeletons.module.scss deleted file mode 100644 index ffc7909f..00000000 --- a/src/components/PageControls/PageControlsSkeletons/PageControlsSkeletons.module.scss +++ /dev/null @@ -1,28 +0,0 @@ -@use '../../../shared/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; - } -} diff --git a/src/entities/BlogCard/ui/BlogCard.module.scss b/src/entities/BlogCard/ui/BlogCard.module.scss index 8a84ddfe..c059f666 100644 --- a/src/entities/BlogCard/ui/BlogCard.module.scss +++ b/src/entities/BlogCard/ui/BlogCard.module.scss @@ -5,12 +5,17 @@ display: flex; flex-direction: column; justify-content: space-between; - gap: 15px; + gap: 8px; width: 100%; user-select: none; @include media.respond-to('middle') { width: 260px; + gap: 7px; + } + + &_blog { + width: 100%; } } @@ -18,14 +23,30 @@ line-height: 22px; font-size: 16px; font-weight: 500; + padding-top: 12px; transition: 0.5s; } +.subheading { + font-size: 17px; +} + +.imageContainer { + position: relative; + display: flex; +} + .image { width: 100%; border-radius: 10px; object-fit: cover; - transition: 0.25s ease-in-out; + transition: 0.25s; + + &_blog { + @include media.respond-to('small-middle') { + height: 418px; + } + } } .noImage { @@ -41,5 +62,16 @@ } .blogCard:hover .image { - transform: scale(1.025); + transform: scale(1.02); +} + +.tags { + position: absolute; + top: 0; + left: 0; + display: flex; + flex-wrap: wrap; + gap: 10px; + padding: 20px; + cursor: auto; } diff --git a/src/entities/BlogCard/ui/BlogCard.stories.tsx b/src/entities/BlogCard/ui/BlogCard.stories.tsx index 35f7d03e..a91ab975 100644 --- a/src/entities/BlogCard/ui/BlogCard.stories.tsx +++ b/src/entities/BlogCard/ui/BlogCard.stories.tsx @@ -1,6 +1,6 @@ import type { Meta, StoryObj } from '@storybook/react' -import Img1 from '@/assets/images/blog/img-blog-01.png' +import blogImage from '@/assets/images/blog/img-blog-01.png' import BlogCard from './BlogCard' @@ -16,11 +16,24 @@ const meta = { export default meta type Story = StoryObj -export const Default: Story = { - args: { - id: 1, - image: Img1, - title: 'Покупай и не жди. До -50% на весь электротранспорт!', - date: '2022-07-8' - } +export const Default: Story = () => { + const id = 1 + const image = blogImage + const date = '2022-07-8' + const title = 'Дайджест интересных материалов для мобильного разработчика' + const tags = [{ name: 'тег-1' }, { name: 'тег-2' }, { name: 'тег-3' }] + + return ( +
+ +
+ ) +} + +Default.args = { + id: 1, + image: blogImage, + date: '2022-07-8', + title: 'Дайджест интересных материалов для мобильного разработчика', + tags: [{ name: 'тег-1' }, { name: 'тег-2' }, { name: 'тег-3' }] } diff --git a/src/entities/BlogCard/ui/BlogCard.tsx b/src/entities/BlogCard/ui/BlogCard.tsx index e732eb94..16914cb8 100644 --- a/src/entities/BlogCard/ui/BlogCard.tsx +++ b/src/entities/BlogCard/ui/BlogCard.tsx @@ -1,27 +1,39 @@ import { FC, useMemo } from 'react' import NoImage from '@/assets/icons/image-not-found-icon.svg' +import BlogItemForContainer from '@/entities/BlogItemForContainer' +import TagButton from '@/entities/TagButton' import Heading, { HeadingType } from '@/shared/ui/Heading/Heading' import Link from '@/shared/ui/Link/Link' import Subheading from '@/shared/ui/Subheading/Subheading' import styles from './BlogCard.module.scss' -type Props = { +interface IBlogCard { id: number image: string title: string date: string + tags?: TTag[] + views?: number + isBlog?: boolean +} + +type TTag = { + name: string } /** - * Компонент BlogCard - это карточка блога для BlogBlock. + * Компонент BlogCard - это карточка блога для BlogBlock и BlogMain. * @param {string} image - картинка блога * @param {string} title - заголовок блога * @param {string} date - дата блога + * @param {string} tags - теги блога + * @param {number} views - количество просмотров + * @param {boolean} isBlog - булевое значение для отрисовки тегов */ -const BlogCard: FC = ({ image, date, title }) => { +const BlogCard: FC = ({ image, date, title, tags, views = 0, isBlog = false }) => { const newDate = useMemo(() => { const _parsedDate = new Date(date) const year = _parsedDate.getFullYear() @@ -30,17 +42,41 @@ const BlogCard: FC = ({ image, date, title }) => { return `${formatter}, ${year}` }, [date]) + const blogTags = useMemo( + () => + tags?.map((tag, index) => ( +
  • + +
  • + )), + [] + ) + return ( - + {image ? ( - {'блог'} +
    + {'блог'} + {isBlog && ( + <> +
      {blogTags}
    + + + )} +
    ) : ( - + )} + {title} - {newDate} + {newDate} ) } diff --git a/src/entities/BlogCategories/index.tsx b/src/entities/BlogCategories/index.tsx new file mode 100644 index 00000000..3515a8a7 --- /dev/null +++ b/src/entities/BlogCategories/index.tsx @@ -0,0 +1,2 @@ +import BlogCategories from './ui/BlogCategories' +export default BlogCategories diff --git a/src/entities/BlogCategories/ui/BlogCategories.stories.tsx b/src/entities/BlogCategories/ui/BlogCategories.stories.tsx new file mode 100644 index 00000000..c6e4664f --- /dev/null +++ b/src/entities/BlogCategories/ui/BlogCategories.stories.tsx @@ -0,0 +1,29 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import { blogPageData } from '@/mockData/blogPageData' + +import BlogCategories from './BlogCategories' + +const meta = { + title: 'entities/BlogCategories', + component: BlogCategories, + parameters: { + layout: 'centered' + }, + tags: ['autodocs'] +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = () => { + return ( +
    + {}} /> +
    + ) +} + +Default.args = { + cards: blogPageData +} diff --git a/src/entities/BlogCategories/ui/BlogCategories.tsx b/src/entities/BlogCategories/ui/BlogCategories.tsx new file mode 100644 index 00000000..0dab1d0d --- /dev/null +++ b/src/entities/BlogCategories/ui/BlogCategories.tsx @@ -0,0 +1,79 @@ +import { FC, useMemo } from 'react' + +import { TBlogItem } from '@/models/BlogItemModel' +import { Button } from '@/shared/ui/Button/Button' +import Heading, { HeadingType } from '@/shared/ui/Heading/Heading' +import Scroll from '@/shared/ui/Scroll/Scroll' + +import styles from './blog-categories.module.scss' + +interface IBlogCategories { + cards: TBlogItem[] + filterItems: (curcat?: string) => void +} + +/** + * Компонент BlogCategories используется в компоненте SideBarBlog, делает фильтрацию по категориям + * @param {Array} cards - массив карточек блога + * @param {function} filterItems - функция фильтровки категорий + */ + +const BlogCategories: FC = ({ cards, filterItems }) => { + const currentCategory = useMemo( + () => + cards.map(item => { + return item.category + }), + [cards] + ) + + const result: { + key?: string + count: number + }[] = [] + // Create a unique list of items to loop over + // Add each item to the result list + ;[...new Set(currentCategory)].forEach(item => + useMemo( + () => + result.push({ + key: item, + // Get the count of items of the current type + count: currentCategory.filter(i => i == item).length + }), + [result] + ) + ) + + const Categories = useMemo( + () => + result.map(item => { + return ( +
  • + +
  • + ) + }), + [currentCategory] + ) + + return ( +
    + + Категории + + + {Categories} + +
    + ) +} + +export default BlogCategories diff --git a/src/entities/BlogCategories/ui/blog-categories.module.scss b/src/entities/BlogCategories/ui/blog-categories.module.scss new file mode 100644 index 00000000..004cf9bb --- /dev/null +++ b/src/entities/BlogCategories/ui/blog-categories.module.scss @@ -0,0 +1,54 @@ +@use '@/shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/mixins' as media; + +.blogCategories { + display: flex; + flex-direction: column; + gap: 20px; + + &__title { + display: block; + + @include media.respond-to('large') { + display: none; + } + } + + &__list { + display: flex; + flex-direction: column; + gap: 5px; + + @include media.respond-to('large') { + flex-direction: row; + padding-bottom: 10px; + } + } + + &__button { + display: flex; + justify-content: space-between; + align-items: center; + gap: 20px; + width: 100%; + background: var.$body-bg; + border-radius: 5px; + font-size: 14px; + color: var.$body-color; + fill: var.$body-color; + padding: 10px 15px; + transition: 0.25s; + user-select: none; + + &:hover { + color: var.$header-color; + } + + @include media.respond-to('large') { + width: 100%; + background: var.$white; + padding-top: 0; + padding-bottom: 0; + } + } +} diff --git a/src/entities/BlogItemForContainer/index.tsx b/src/entities/BlogItemForContainer/index.tsx new file mode 100644 index 00000000..d2e6ed54 --- /dev/null +++ b/src/entities/BlogItemForContainer/index.tsx @@ -0,0 +1,2 @@ +import BlogItemForContainer from './ui/BlogItemForContainer' +export default BlogItemForContainer diff --git a/src/entities/BlogItemForContainer/ui/BlogItemForContainer.stories.tsx b/src/entities/BlogItemForContainer/ui/BlogItemForContainer.stories.tsx new file mode 100644 index 00000000..ae22c633 --- /dev/null +++ b/src/entities/BlogItemForContainer/ui/BlogItemForContainer.stories.tsx @@ -0,0 +1,37 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import BlogItemForContainer from './BlogItemForContainer' + +const meta = { + title: 'entities/BlogItemForContainer', + component: BlogItemForContainer, + parameters: { + layout: 'centered' + }, + tags: ['autodocs'] +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = () => { + const views = 107 + const reviews = 15 + + return ( +
    + +
    + ) +} + +Default.args = { + views: 107, + reviews: 15 +} diff --git a/src/entities/BlogItemForContainer/ui/BlogItemForContainer.tsx b/src/entities/BlogItemForContainer/ui/BlogItemForContainer.tsx new file mode 100644 index 00000000..d933e450 --- /dev/null +++ b/src/entities/BlogItemForContainer/ui/BlogItemForContainer.tsx @@ -0,0 +1,36 @@ +import { FC } from 'react' + +import IconReview from '@/assets/images/blogMainItem/icon-comments.svg' +import IconView from '@/assets/images/blogMainItem/icon-views.svg' + +import styles from './blog-item-for-container.module.scss' + +interface IBlogItemForContainer { + views: number + reviews: number + className?: string +} + +/** + * Компонент BlogItemForContainer показывает просмотры и коментарии в карточке блога BlogCard + * @param {number} views - количество просмотров + * @param {number} reviews - количество коментариев + * @param {string} className - дополнительный класс SCSS + */ + +const BlogItemForContainer: FC = ({ views, reviews, className }) => { + return ( +
      +
    • + + {views} +
    • +
    • + + {reviews} +
    • +
    + ) +} + +export default BlogItemForContainer diff --git a/src/entities/BlogItemForContainer/ui/blog-item-for-container.module.scss b/src/entities/BlogItemForContainer/ui/blog-item-for-container.module.scss new file mode 100644 index 00000000..af3b81b8 --- /dev/null +++ b/src/entities/BlogItemForContainer/ui/blog-item-for-container.module.scss @@ -0,0 +1,22 @@ +@use '@/shared/styles/utils/variables' as var; + +.blogItemForContainer { + position: absolute; + bottom: 0; + left: 0; + right: 0; + display: flex; + gap: 20px; + width: 100%; + padding: 20px; + cursor: auto; + + &__info { + display: flex; + align-items: center; + gap: 5px; + font-size: 15px; + font-weight: 500; + color: var.$white; + } +} diff --git a/src/entities/BlogMainItem/index.tsx b/src/entities/BlogMainItem/index.tsx new file mode 100644 index 00000000..653ff866 --- /dev/null +++ b/src/entities/BlogMainItem/index.tsx @@ -0,0 +1,2 @@ +import BlogMainItem from './ui/BlogMainItem' +export default BlogMainItem diff --git a/src/entities/BlogMainItem/ui/BlogMainItem.tsx b/src/entities/BlogMainItem/ui/BlogMainItem.tsx new file mode 100644 index 00000000..e5264227 --- /dev/null +++ b/src/entities/BlogMainItem/ui/BlogMainItem.tsx @@ -0,0 +1,40 @@ +import { FC, useMemo } from 'react' + +import DotIcon from '@/assets/images/blogMainItem/icon-dot.svg' +import BlogItemForContainer from '@/entities/BlogItemForContainer' +import TagButton from '@/entities/TagButton' +import { blogMainItemData } from '@/mockData/blogMainItemData' +import Heading, { HeadingType } from '@/shared/ui/Heading/Heading' +import Link from '@/shared/ui/Link/Link' +import Subheading from '@/shared/ui/Subheading/Subheading' + +import styles from './blog-main-item.module.scss' + +const BlogMainItem: FC = () => { + const tags = useMemo( + () => + blogMainItemData.tags.map((tag, index) => ( +
  • + +
  • + )), + [] + ) + + return ( + + {blogMainItemData.alt} +
      {tags}
    + + {blogMainItemData.title} + +
    + + + 8 мая, 2022 +
    + + ) +} + +export default BlogMainItem diff --git a/src/entities/BlogMainItem/ui/blog-main-item.module.scss b/src/entities/BlogMainItem/ui/blog-main-item.module.scss new file mode 100644 index 00000000..953aacb4 --- /dev/null +++ b/src/entities/BlogMainItem/ui/blog-main-item.module.scss @@ -0,0 +1,61 @@ +@use '@/shared/styles/utils/variables' as var; + +.blogMainItem { + position: relative; + display: flex; + + &__tags { + position: absolute; + top: 0; + left: 0; + display: flex; + flex-wrap: wrap; + gap: 10px; + padding: 30px; + cursor: auto; + } + + &__title { + position: absolute; + bottom: 0; + left: 0; + display: flex; + width: 100%; + max-width: 540px; + color: var.$white; + padding: 30px; + } + + &__infoBox { + position: absolute; + bottom: 0; + right: 0; + display: flex; + align-items: center; + gap: 30px; + padding: 30px; + cursor: auto; + } + + &__blogItem { + position: relative; + width: fit-content; + padding: 0; + } + + &__subheading { + font-size: 17px; + color: var.$white; + } +} + +.image { + width: 100%; + border-radius: 10px; + object-fit: cover; + transition: 0.15s; +} + +.blogMainItem:hover .image { + transform: scale(1.02); +} diff --git a/src/entities/BlogTags/index.tsx b/src/entities/BlogTags/index.tsx new file mode 100644 index 00000000..f9a5918a --- /dev/null +++ b/src/entities/BlogTags/index.tsx @@ -0,0 +1,2 @@ +import BlogTags from './ui/BlogTags' +export default BlogTags diff --git a/src/entities/BlogTags/ui/BlogTags.stories.tsx b/src/entities/BlogTags/ui/BlogTags.stories.tsx new file mode 100644 index 00000000..ed991b20 --- /dev/null +++ b/src/entities/BlogTags/ui/BlogTags.stories.tsx @@ -0,0 +1,29 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import { blogPageData } from '@/mockData/blogPageData' + +import BlogTags from './BlogTags' + +const meta = { + title: 'entities/BlogTags', + component: BlogTags, + parameters: { + layout: 'centered' + }, + tags: ['autodocs'] +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = () => { + return ( +
    + {}} /> +
    + ) +} + +Default.args = { + cards: blogPageData +} diff --git a/src/entities/BlogTags/ui/BlogTags.tsx b/src/entities/BlogTags/ui/BlogTags.tsx new file mode 100644 index 00000000..bc3f0bd8 --- /dev/null +++ b/src/entities/BlogTags/ui/BlogTags.tsx @@ -0,0 +1,65 @@ +import { FC, useMemo } from 'react' + +import { TBlogItem } from '@/models/BlogItemModel' +import { Button } from '@/shared/ui/Button/Button' +import Paragraph from '@/shared/ui/Paragraph/Paragraph' + +import styles from './blog-tags.module.scss' + +interface IBlogTags { + cards: TBlogItem[] + filterItems: (curcat: string) => void +} + +/** + * Компонент BlogTags используется в компоненте SideBarBlog, делает фильтрацию по тегам + * @param {Array} cards - массив карточек блога + * @param {function} filterItems - функция фильтровки тегов + */ + +const BlogTags: FC = ({ cards, filterItems }) => { + const tags = useMemo( + () => + cards.map(item => { + return item.tags + }), + [cards] + ) + + const tagsAll = useMemo( + () => + tags.reduce(function (arr, e) { + return arr.concat(e) + }), + [tags] + ) + + const arrayOfTags = Array.from(new Set(tagsAll)) + + const uniqueTags = useMemo( + () => + arrayOfTags.map(item => { + return ( +
  • + +
  • + ) + }), + arrayOfTags + ) + + return ( +
    + Тэги +
      {uniqueTags}
    +
    + ) +} + +export default BlogTags diff --git a/src/entities/BlogTags/ui/blog-tags.module.scss b/src/entities/BlogTags/ui/blog-tags.module.scss new file mode 100644 index 00000000..87872a3a --- /dev/null +++ b/src/entities/BlogTags/ui/blog-tags.module.scss @@ -0,0 +1,29 @@ +@use '@/shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/mixins' as media; + +.blogTags { + display: flex; + flex-direction: column; + gap: 20px; + + &__list { + display: flex; + flex-wrap: wrap; + gap: 5px; + } + + &__button { + display: flex; + justify-content: center; + align-items: center; + background: var.$body-bg; + font-size: 14px; + color: var.$body-color; + padding: 0 12px; + transition: 0.25s; + + &:hover { + color: var.$header-color; + } + } +} diff --git a/src/widgets/Carousel/Carousel.module.scss b/src/entities/Carousel/Carousel.module.scss similarity index 80% rename from src/widgets/Carousel/Carousel.module.scss rename to src/entities/Carousel/Carousel.module.scss index 14f2e05b..eee8fbeb 100644 --- a/src/widgets/Carousel/Carousel.module.scss +++ b/src/entities/Carousel/Carousel.module.scss @@ -1,4 +1,4 @@ -@use '../../shared/styles/utils/variables' as color; +@use '@/shared/styles/utils/variables' as var; .carouselContainer { position: relative; @@ -40,9 +40,9 @@ width: 100%; max-width: 100px; height: 2px; - background-color: color.$body-color-light-grey; + background-color: var.$body-color-light-grey; } .dot.active { - background-color: color.$theme-primary-color; + background-color: var.$theme-primary-color; } diff --git a/src/widgets/Carousel/Carousel.stories.tsx b/src/entities/Carousel/Carousel.stories.tsx similarity index 100% rename from src/widgets/Carousel/Carousel.stories.tsx rename to src/entities/Carousel/Carousel.stories.tsx diff --git a/src/widgets/Carousel/Carousel.tsx b/src/entities/Carousel/Carousel.tsx similarity index 100% rename from src/widgets/Carousel/Carousel.tsx rename to src/entities/Carousel/Carousel.tsx diff --git a/src/entities/CategoryCard/CategoryCard.module.scss b/src/entities/CategoryCard/CategoryCard.module.scss index 7e4c55f4..4d7fc283 100644 --- a/src/entities/CategoryCard/CategoryCard.module.scss +++ b/src/entities/CategoryCard/CategoryCard.module.scss @@ -1,15 +1,21 @@ @use '../../shared/styles/utils/variables' as var; .category-card { - width: 255px; - height: 183px; + width: 100%; + min-height: 183px; + padding: 5px; border-radius: 10px; box-sizing: border-box; background-color: white; display: flex; - gap: auto; flex-direction: column; justify-content: space-between; + cursor: pointer; + transition: transform 0.3s; + + &:hover { + transform: scale(1.05); + } } .category-card__img { diff --git a/src/entities/CategoryCard/CategoryCard.tsx b/src/entities/CategoryCard/CategoryCard.tsx index acfca18d..e8b7b47e 100644 --- a/src/entities/CategoryCard/CategoryCard.tsx +++ b/src/entities/CategoryCard/CategoryCard.tsx @@ -1,10 +1,11 @@ -import { FC } from 'react' +import { type FC } from 'react' +import { useNavigate } from 'react-router' -import { TCategory } from '@/shared/model/types/CategoryModel' +import defaultCard from '@/assets/images/categoryCards/placeholder-1200x800.png' +import { Routes } from '@/shared/config/routerConfig/routes' +import type { TCategory } from '@/shared/model/types/CategoryModel' import Paragraph from '@/shared/ui/Paragraph/Paragraph' -import card1 from '../../assets/images/categoryCards/placeholder-1200x800.png' - import styles from './CategoryCard.module.scss' interface CategoryCardProps { @@ -12,11 +13,21 @@ interface CategoryCardProps { } export const CategoryCard: FC = ({ category }) => { + const navigate = useNavigate() + + const clickHandle = () => { + navigate(`${Routes.CATEGORIES}/${category.slug}?id=${category.id}`) + } + return ( -
    +
    {category && ( <> - {category.name} + {category.name} {category.name} )} diff --git a/src/entities/CategoryCard/getCategoryCard.tsx b/src/entities/CategoryCard/getCategoryCard.tsx deleted file mode 100644 index fb904760..00000000 --- a/src/entities/CategoryCard/getCategoryCard.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { createAsyncThunk } from '@reduxjs/toolkit' - -import { ThunkConfig } from '@/app/providers/StoreProvider/config/StateSchema' -import { apiErrorIdentify } from '@/shared/api/apiErrorIdentify' -import { ApiError, ApiErrorTypes, ApiRoutes } from '@/shared/api/types' -import { ACTION_GET_СATEGORY } from '@/shared/constants/constants' - -import { CategoryInfo } from './types' - -export const getCategoryCard = createAsyncThunk>( - ACTION_GET_СATEGORY, - async (id: number, thunkAPI) => { - const { rejectWithValue, extra } = thunkAPI - try { - const { data } = await extra.api.get(`api/${ApiRoutes.CATEGORIES}`) - return data - } catch (error) { - return rejectWithValue(apiErrorIdentify(error, ApiErrorTypes.DATA_EMPTY_ERROR)) - } - } -) diff --git a/src/entities/CategoryCard/types.tsx b/src/entities/CategoryCard/types.tsx deleted file mode 100644 index be8f54d0..00000000 --- a/src/entities/CategoryCard/types.tsx +++ /dev/null @@ -1,14 +0,0 @@ -// Тип данных для категории -export interface Category { - id: string - name: string - image: string -} - -export interface CategoryInfo { - name: string - count: number - next: string - previous: string - results: Category[] -} diff --git a/src/entities/NewsCard/ui/NewsCard.stories.tsx b/src/entities/NewsCard/ui/NewsCard.stories.tsx index cd3a9fc5..7e22ea8c 100644 --- a/src/entities/NewsCard/ui/NewsCard.stories.tsx +++ b/src/entities/NewsCard/ui/NewsCard.stories.tsx @@ -15,7 +15,7 @@ export default meta type Story = StoryObj export const Default: Story = () => { - const image = 'http://gealit.ru/media/news/18.png' + const image = 'https://gealit.ru/media/news/img-gallery-04-750x500.webp' const date = '2022-05-15' const title = 'Покупай и не жди. До -50% на весь электротранспорт!' diff --git a/src/features/ProductAvailability/ProductAvailability.module.scss b/src/entities/ProductAvailability/ProductAvailability.module.scss similarity index 90% rename from src/features/ProductAvailability/ProductAvailability.module.scss rename to src/entities/ProductAvailability/ProductAvailability.module.scss index d251ec08..c15deb12 100644 --- a/src/features/ProductAvailability/ProductAvailability.module.scss +++ b/src/entities/ProductAvailability/ProductAvailability.module.scss @@ -1,4 +1,4 @@ -@use '../../shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/variables' as var; .product-card__info { display: flex; diff --git a/src/features/ProductAvailability/ProductAvailability.tsx b/src/entities/ProductAvailability/ProductAvailability.tsx similarity index 100% rename from src/features/ProductAvailability/ProductAvailability.tsx rename to src/entities/ProductAvailability/ProductAvailability.tsx diff --git a/src/entities/ProductEntity/ui/ProductEntity/ProductEntity.module.scss b/src/entities/ProductEntity/ui/ProductEntity/ProductEntity.module.scss index 8c10f0d4..55e6ef01 100644 --- a/src/entities/ProductEntity/ui/ProductEntity/ProductEntity.module.scss +++ b/src/entities/ProductEntity/ui/ProductEntity/ProductEntity.module.scss @@ -1,56 +1,58 @@ -@use '../../../../shared/styles/utils/variables' as var; -@use '../../../../shared/styles/utils/mixins' as media; +@use '@/shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/mixins' as media; -.description { - display: flex; - align-items: center; - padding: 10px; - background: var.$white; - border-radius: 10px; - height: 110px; - width: 60%; -} - -.frame { - width: 90px; - height: 90px; - display: flex; +.productEntity { + grid-area: productEntity; + display: grid; + grid-template-columns: 40% 1fr; align-items: center; - justify-content: center; - padding: 10px; - margin: 0 20px 0 0; - background: var.$white; - border-radius: 5px; + gap: 20px; + width: 100%; + max-width: 500px; @include media.respond-to('large') { - border: 1px solid var.$light-grey; + max-width: 100%; + } + + @include media.respond-to('middle') { + align-items: flex-start; + gap: 10px; + } + + &__imageBox { + display: flex; + align-items: center; + justify-content: center; } } .image { - display: flex; - max-height: 100%; - width: 70px; - height: 70px; + width: 100px; object-fit: cover; } -.description_wrapper { +.description { display: flex; flex-direction: column; - max-height: 80px; + gap: 2px; + width: 100%; + + @include media.respond-to('middle') { + flex-direction: column; + max-width: 100%; + } } .name { display: flex; font-size: 15px; - line-height: 1.35; font-weight: 700; color: var.$body-color; text-overflow: ellipsis; overflow: hidden; - - @include media.respond-to('large') { - width: 100%; + transition: 0.25s; + + &:hover { + color: var.$theme-primary-color; } } diff --git a/src/entities/ProductEntity/ui/ProductEntity/ProductEntity.tsx b/src/entities/ProductEntity/ui/ProductEntity/ProductEntity.tsx index 321033e9..1cd8beb0 100644 --- a/src/entities/ProductEntity/ui/ProductEntity/ProductEntity.tsx +++ b/src/entities/ProductEntity/ui/ProductEntity/ProductEntity.tsx @@ -1,6 +1,7 @@ import { type FC } from 'react' import { IProduct } from '@/shared/model/types/ProductModel' +import Link from '@/shared/ui/Link/Link' import Subheading from '@/shared/ui/Subheading/Subheading' import styles from './ProductEntity.module.scss' @@ -9,23 +10,24 @@ import styles from './ProductEntity.module.scss' * Компонент служит для отображения товаров, пришедших с сервера. * @param {IImagesData[]} images-картика с изображением продукта; * @param {string} name- название продукта; - * @param {number} id -артикул продукта; + * @param {number} code -артикул продукта; * @param {number} price -стоимость продукта; * @param {string} currency - валюта, в которой обозначена стоимость; */ -export const ProductEntity: FC = product => { +export const ProductEntity: FC = ({ ...product }) => { return ( -
    -
    - {(product.images.length > 0 && ( - {'product'} - )) || <>} -
    -
    - {product.id} - {product.name} +
    +
    + product
    + +
    + {product.code} + + {product.name} + +
    ) } diff --git a/src/features/ProductImgCarousel/ProductImgCarousel.module.scss b/src/entities/ProductImgCarousel/ProductImgCarousel.module.scss similarity index 100% rename from src/features/ProductImgCarousel/ProductImgCarousel.module.scss rename to src/entities/ProductImgCarousel/ProductImgCarousel.module.scss diff --git a/src/features/ProductImgCarousel/ProductImgCarousel.stories.tsx b/src/entities/ProductImgCarousel/ProductImgCarousel.stories.tsx similarity index 100% rename from src/features/ProductImgCarousel/ProductImgCarousel.stories.tsx rename to src/entities/ProductImgCarousel/ProductImgCarousel.stories.tsx diff --git a/src/features/ProductImgCarousel/ProductImgCarousel.tsx b/src/entities/ProductImgCarousel/ProductImgCarousel.tsx similarity index 86% rename from src/features/ProductImgCarousel/ProductImgCarousel.tsx rename to src/entities/ProductImgCarousel/ProductImgCarousel.tsx index 5f465496..6d6905c7 100644 --- a/src/features/ProductImgCarousel/ProductImgCarousel.tsx +++ b/src/entities/ProductImgCarousel/ProductImgCarousel.tsx @@ -1,10 +1,10 @@ import { useState, type FC, Dispatch, SetStateAction } from 'react' +import { ImgCarousel } from '@/entities/ProductImgCarousel/ui/ImgCarousel/ImgCarousel' +import { PreviewCarousel } from '@/entities/ProductImgCarousel/ui/PreviewCarousel/PreviewCarousel' import type { IImage } from '@/shared/model/types/ImageModel' import styles from './ProductImgCarousel.module.scss' -import { ImgCarousel } from './ui/ImgCarousel/ImgCarousel' -import { PreviewCarousel } from './ui/PreviewCarousel/PreviewCarousel' interface IProductImgCarouselProps { imgList: IImage[] diff --git a/src/features/ProductImgCarousel/model/constants/constants.ts b/src/entities/ProductImgCarousel/model/constants/constants.ts similarity index 100% rename from src/features/ProductImgCarousel/model/constants/constants.ts rename to src/entities/ProductImgCarousel/model/constants/constants.ts diff --git a/src/features/ProductImgCarousel/model/functions/functions.ts b/src/entities/ProductImgCarousel/model/functions/functions.ts similarity index 100% rename from src/features/ProductImgCarousel/model/functions/functions.ts rename to src/entities/ProductImgCarousel/model/functions/functions.ts diff --git a/src/features/ProductImgCarousel/model/types/productImgCarouselType.ts b/src/entities/ProductImgCarousel/model/types/productImgCarouselType.ts similarity index 100% rename from src/features/ProductImgCarousel/model/types/productImgCarouselType.ts rename to src/entities/ProductImgCarousel/model/types/productImgCarouselType.ts diff --git a/src/features/ProductImgCarousel/ui/ImgCarousel/ImgCarousel.module.scss b/src/entities/ProductImgCarousel/ui/ImgCarousel/ImgCarousel.module.scss similarity index 100% rename from src/features/ProductImgCarousel/ui/ImgCarousel/ImgCarousel.module.scss rename to src/entities/ProductImgCarousel/ui/ImgCarousel/ImgCarousel.module.scss diff --git a/src/features/ProductImgCarousel/ui/ImgCarousel/ImgCarousel.tsx b/src/entities/ProductImgCarousel/ui/ImgCarousel/ImgCarousel.tsx similarity index 94% rename from src/features/ProductImgCarousel/ui/ImgCarousel/ImgCarousel.tsx rename to src/entities/ProductImgCarousel/ui/ImgCarousel/ImgCarousel.tsx index 1c9e3f37..cfed3e29 100644 --- a/src/features/ProductImgCarousel/ui/ImgCarousel/ImgCarousel.tsx +++ b/src/entities/ProductImgCarousel/ui/ImgCarousel/ImgCarousel.tsx @@ -1,11 +1,10 @@ import React, { FC, useEffect, useMemo, useState } from 'react' +import { IMG_SIZE_PAGE, IMG_SIZE_POPUP } from '@/entities/ProductImgCarousel/model/constants/constants' +import { TImgCarouselProps } from '@/entities/ProductImgCarousel/model/types/productImgCarouselType' import { bodyScrollControl } from '@/shared/libs/helpers/popupHelper' import { useResize } from '@/shared/libs/hooks/useResize' -import { IMG_SIZE_PAGE, IMG_SIZE_POPUP } from '../../model/constants/constants' -import { TImgCarouselProps } from '../../model/types/productImgCarouselType' - import styles from './ImgCarousel.module.scss' /** diff --git a/src/features/ProductImgCarousel/ui/PreviewCarousel/PreviewCarousel.module.scss b/src/entities/ProductImgCarousel/ui/PreviewCarousel/PreviewCarousel.module.scss similarity index 100% rename from src/features/ProductImgCarousel/ui/PreviewCarousel/PreviewCarousel.module.scss rename to src/entities/ProductImgCarousel/ui/PreviewCarousel/PreviewCarousel.module.scss diff --git a/src/features/ProductImgCarousel/ui/PreviewCarousel/PreviewCarousel.tsx b/src/entities/ProductImgCarousel/ui/PreviewCarousel/PreviewCarousel.tsx similarity index 94% rename from src/features/ProductImgCarousel/ui/PreviewCarousel/PreviewCarousel.tsx rename to src/entities/ProductImgCarousel/ui/PreviewCarousel/PreviewCarousel.tsx index 35efac3d..0f8a4f4f 100644 --- a/src/features/ProductImgCarousel/ui/PreviewCarousel/PreviewCarousel.tsx +++ b/src/entities/ProductImgCarousel/ui/PreviewCarousel/PreviewCarousel.tsx @@ -2,13 +2,15 @@ import { type FC, useState, useEffect, useMemo, Dispatch, SetStateAction, MouseE import IconArrowDown from '@/assets/icons/IconArrowDown.svg' import IconArrowUp from '@/assets/icons/IconArrowUp.svg' +import { getDisplayedIndex, slicedImgList } from '@/entities/ProductImgCarousel/model/functions/functions' +import type { + TDisplayedImgList, + TChangeImgArgs +} from '@/entities/ProductImgCarousel/model/types/productImgCarouselType' import type { IImage } from '@/shared/model/types/ImageModel' import { Button, ButtonTheme, ButtonDesign, ButtonSize } from '@/shared/ui/Button/Button' import { DISPLAYED_IMAGES_NUMBER } from '@/widgets/Product/model/constants/constants' -import { getDisplayedIndex, slicedImgList } from '../../model/functions/functions' -import type { TDisplayedImgList, TChangeImgArgs } from '../../model/types/productImgCarouselType' - import styles from './PreviewCarousel.module.scss' interface IPreviewCarouselProps { diff --git a/src/entities/ReviewCard/ui/ReviewCardFeedback/ReviewCardFeedback.tsx b/src/entities/ReviewCard/ui/ReviewCardFeedback/ReviewCardFeedback.tsx index 449f0b77..d628ba70 100644 --- a/src/entities/ReviewCard/ui/ReviewCardFeedback/ReviewCardFeedback.tsx +++ b/src/entities/ReviewCard/ui/ReviewCardFeedback/ReviewCardFeedback.tsx @@ -55,7 +55,7 @@ export const ReviewCardFeedback: FC = ({ pk, text, sco {text} {newDate} - + Читать полный отзыв
    diff --git a/src/entities/ReviewCard/ui/ReviewCardStore/ReviewCardStore.tsx b/src/entities/ReviewCard/ui/ReviewCardStore/ReviewCardStore.tsx index d6b1f7cc..5ace4ab6 100644 --- a/src/entities/ReviewCard/ui/ReviewCardStore/ReviewCardStore.tsx +++ b/src/entities/ReviewCard/ui/ReviewCardStore/ReviewCardStore.tsx @@ -29,7 +29,7 @@ export const ReviewCardStore: FC = ({ score }) => { {FEEDBACK_STORE_COMMENT} Вы можете  - + оставить отзыв   о нашем магазине или  diff --git a/src/entities/SideBarEntity/model/functions/sideBarOptions.ts b/src/entities/SideBarEntity/model/functions/sideBarOptions.ts index ac927cd8..4c41bd79 100644 --- a/src/entities/SideBarEntity/model/functions/sideBarOptions.ts +++ b/src/entities/SideBarEntity/model/functions/sideBarOptions.ts @@ -18,7 +18,7 @@ const noUser = [ title: 'Мои данные', routes: [ { subtitle: 'Вход', route: Routes.LOGIN }, - { subtitle: 'Регистрация', route: Routes.HOME }, // '/create-account' - данного роута пока нет + { subtitle: 'Регистрация', route: Routes.REGISTRATION }, { subtitle: 'Забыли пароль?', route: Routes.HOME }, // '/forgot-password' - данного роута пока нет { subtitle: 'Личный Кабинет', route: Routes.ACCOUNT } ] diff --git a/src/entities/TagButton/index.tsx b/src/entities/TagButton/index.tsx new file mode 100644 index 00000000..1d53d01a --- /dev/null +++ b/src/entities/TagButton/index.tsx @@ -0,0 +1,2 @@ +import TagButton from './ui/TagButton' +export default TagButton diff --git a/src/entities/TagButton/ui/TagButton.module.scss b/src/entities/TagButton/ui/TagButton.module.scss new file mode 100644 index 00000000..6e552f00 --- /dev/null +++ b/src/entities/TagButton/ui/TagButton.module.scss @@ -0,0 +1,19 @@ +@use '@/shared/styles/utils/variables' as var; + +.tagButton { + display: flex; + align-items: center; + background: rgb(247 247 251 / 20%); + border-radius: 5px; + font-size: 14px; + line-height: 14px; + color: var.$white; + padding: 8px 12px; + cursor: pointer; + transition: 0.25s; + + &:hover { + background: var.$white; + color: var.$body-color; + } +} diff --git a/src/entities/TagButton/ui/TagButton.stories.tsx b/src/entities/TagButton/ui/TagButton.stories.tsx new file mode 100644 index 00000000..34d70016 --- /dev/null +++ b/src/entities/TagButton/ui/TagButton.stories.tsx @@ -0,0 +1,38 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import TagButton from './TagButton' + +const meta = { + title: 'entities/TagButton', + component: TagButton, + parameters: { + layout: 'centered' + }, + tags: ['autodocs'] +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = () => { + const tag = 'название тега' + + return ( +
    + +
    + ) +} + +Default.args = { + tag: 'название тега' +} diff --git a/src/entities/TagButton/ui/TagButton.tsx b/src/entities/TagButton/ui/TagButton.tsx new file mode 100644 index 00000000..2ef2e2b8 --- /dev/null +++ b/src/entities/TagButton/ui/TagButton.tsx @@ -0,0 +1,19 @@ +import { FC } from 'react' + +import { Button } from '@/shared/ui/Button/Button' + +import styles from './TagButton.module.scss' + +interface ITagButton { + tag: string +} +/** + * Компонент TagButton - это кнопка тега отображается в таких компонентах как BlogCard, BlogTags и других. + * @param {string} tag - заголовок блога + */ + +const TagButton: FC = ({ tag }) => { + return +} + +export default TagButton diff --git a/src/features/WidgetButtonsFunctions/WidgetButtonsFunctions.module.scss b/src/entities/WidgetButtonsFunctions/WidgetButtonsFunctions.module.scss similarity index 100% rename from src/features/WidgetButtonsFunctions/WidgetButtonsFunctions.module.scss rename to src/entities/WidgetButtonsFunctions/WidgetButtonsFunctions.module.scss diff --git a/src/features/WidgetButtonsFunctions/WidgetButtonsFunctions.stories.tsx b/src/entities/WidgetButtonsFunctions/WidgetButtonsFunctions.stories.tsx similarity index 92% rename from src/features/WidgetButtonsFunctions/WidgetButtonsFunctions.stories.tsx rename to src/entities/WidgetButtonsFunctions/WidgetButtonsFunctions.stories.tsx index 3f448eb8..11ab3d5e 100644 --- a/src/features/WidgetButtonsFunctions/WidgetButtonsFunctions.stories.tsx +++ b/src/entities/WidgetButtonsFunctions/WidgetButtonsFunctions.stories.tsx @@ -1,6 +1,6 @@ import { Story, Meta } from '@storybook/react' -import { WidgetButtonsFunctions } from '@/features/WidgetButtonsFunctions/WidgetButtonsFunctions' +import { WidgetButtonsFunctions } from '@/entities/WidgetButtonsFunctions/WidgetButtonsFunctions' import { ECardView } from '@/shared/model/types/common' export default { diff --git a/src/features/WidgetButtonsFunctions/WidgetButtonsFunctions.tsx b/src/entities/WidgetButtonsFunctions/WidgetButtonsFunctions.tsx similarity index 97% rename from src/features/WidgetButtonsFunctions/WidgetButtonsFunctions.tsx rename to src/entities/WidgetButtonsFunctions/WidgetButtonsFunctions.tsx index f8a69472..7fba1a09 100644 --- a/src/features/WidgetButtonsFunctions/WidgetButtonsFunctions.tsx +++ b/src/entities/WidgetButtonsFunctions/WidgetButtonsFunctions.tsx @@ -3,10 +3,10 @@ import { FC } from 'react' import IconCompare from '@/assets/icons/IconCompare.svg' import IconLike from '@/assets/icons/IconLike' +import styles from '@/features/ProductItem/ProductItem.module.scss' import { ECardView } from '@/shared/model/types/common' import { Button, ButtonSize, ButtonTheme } from '@/shared/ui/Button/Button' import { getStylesForCurrentLayout } from '@/shared/ui/ProductLabels/utils/utils' -import styles from '@/widgets/ProductItem/ProductItem.module.scss' import stylesSvg from './WidgetButtonsFunctions.module.scss' diff --git a/src/features/WidgetButtonsPurchase/WidgetButtonsPurchase.module.scss b/src/entities/WidgetButtonsPurchase/WidgetButtonsPurchase.module.scss similarity index 92% rename from src/features/WidgetButtonsPurchase/WidgetButtonsPurchase.module.scss rename to src/entities/WidgetButtonsPurchase/WidgetButtonsPurchase.module.scss index 3f5dca0c..cd640cd7 100644 --- a/src/features/WidgetButtonsPurchase/WidgetButtonsPurchase.module.scss +++ b/src/entities/WidgetButtonsPurchase/WidgetButtonsPurchase.module.scss @@ -9,7 +9,6 @@ .customButton { max-width: 120px; min-height: 50px; - padding: 5px; display: flex; align-items: center; justify-content: center; @@ -24,7 +23,8 @@ svg { width: 25px; - height: 20px; + min-width: 25px; + height: 25px; } &__iconCart { diff --git a/src/features/WidgetButtonsPurchase/WidgetButtonsPurchase.stories.tsx b/src/entities/WidgetButtonsPurchase/WidgetButtonsPurchase.stories.tsx similarity index 89% rename from src/features/WidgetButtonsPurchase/WidgetButtonsPurchase.stories.tsx rename to src/entities/WidgetButtonsPurchase/WidgetButtonsPurchase.stories.tsx index e59e6c03..873f0864 100644 --- a/src/features/WidgetButtonsPurchase/WidgetButtonsPurchase.stories.tsx +++ b/src/entities/WidgetButtonsPurchase/WidgetButtonsPurchase.stories.tsx @@ -1,6 +1,6 @@ import { Story, Meta } from '@storybook/react' -import { WidgetButtonsPurchase } from '@/features/WidgetButtonsPurchase/WidgetButtonsPurchase' +import { WidgetButtonsPurchase } from '@/entities/WidgetButtonsPurchase/WidgetButtonsPurchase' import { ECardView } from '@/shared/model/types/common' export default { @@ -13,6 +13,7 @@ type TWidgetButtonsPurchase = { handleAddToCart: VoidFunction onEyeClick: VoidFunction layout: ECardView + wb_urls: string } const Template: Story = args => diff --git a/src/features/WidgetButtonsPurchase/WidgetButtonsPurchase.tsx b/src/entities/WidgetButtonsPurchase/WidgetButtonsPurchase.tsx similarity index 80% rename from src/features/WidgetButtonsPurchase/WidgetButtonsPurchase.tsx rename to src/entities/WidgetButtonsPurchase/WidgetButtonsPurchase.tsx index a65f904e..233ee874 100644 --- a/src/features/WidgetButtonsPurchase/WidgetButtonsPurchase.tsx +++ b/src/entities/WidgetButtonsPurchase/WidgetButtonsPurchase.tsx @@ -3,6 +3,7 @@ import { FC } from 'react' import IconCart from '@/assets/icons/IconCart.svg' import IconEye from '@/assets/icons/IconEye.svg' +import WB from '@/assets/icons/WB.svg' import { ECardView } from '@/shared/model/types/common' import { Button, ButtonSize, ButtonTheme } from '@/shared/ui/Button/Button' @@ -13,6 +14,7 @@ type TWidgetButtonsPurchase = { handleAddToCart: VoidFunction onEyeClick: VoidFunction layout: ECardView + wb_urls?: string } /** @@ -21,15 +23,21 @@ type TWidgetButtonsPurchase = { * @param {function} handleAddToCart - функция добавления товара в корзину; * @param {function} onEyeClick - функция открытия поп-апа с дополнительной информацией о товаре; * @param {string} layout - текущий вид отображения карточки товара; + * @param {string} wb_urls ссылка на страницу с товаром на WB */ export const WidgetButtonsPurchase: FC = ({ isInCart, handleAddToCart, onEyeClick, - layout + layout, + wb_urls }) => { const size = layout === ECardView.COMPACT ? ButtonSize.S : ButtonSize.XS + const buyWBHandle = () => { + window.open(wb_urls, '_blank') + } + return (
    + {wb_urls && ( + + )} - - -
    - -
    -
      -
    • - -
    • -
    • - -
    • -
    -
    -
    +
  • + + +
    + + +
    - + +
    + + {calculateProductPrice(productWithInfo.amount, String(productWithInfo.product.price))} +  ₽ + + {productWithInfo.product.price} ₽/шт +
    + + +
    +
      +
    • + +
    • +
    • + +
    • +
    +
    +
    +
  • ) } diff --git a/src/features/HeaderMenuModal/HeaderMenuModalCatalog/HeaderMenuModalCatalog.tsx b/src/features/HeaderMenuModal/HeaderMenuModalCatalog/HeaderMenuModalCatalog.tsx index 3c1df450..d334ba4d 100644 --- a/src/features/HeaderMenuModal/HeaderMenuModalCatalog/HeaderMenuModalCatalog.tsx +++ b/src/features/HeaderMenuModal/HeaderMenuModalCatalog/HeaderMenuModalCatalog.tsx @@ -1,10 +1,14 @@ -import { FC } from 'react' +import { type FC } from 'react' +import { useDispatch } from 'react-redux' +import { AppDispatch } from '@/app/providers/StoreProvider/config/store' +import { setCategoryId } from '@/entities/Category/slice/categoryIdSlice' +import { setCategorySlug } from '@/entities/Category/slice/categorySlugSlice' import { Routes } from '@/shared/config/routerConfig/routes' import Link from '@/shared/ui/Link/Link' import HeaderMenuModalHeading from '../HeaderMenuModalHeading/HeaderMenuModalHeading' -import { ICategory } from '../model/types/types' +import { type ICategory } from '../model/types/types' import styles from './HeaderMenuModalCatalog.module.scss' @@ -29,6 +33,16 @@ const HeaderMenuModalCatalog: FC = ({ handleCategory, handleClose }) => { + const dispatch = useDispatch() + + const handleCloseAndDispatch = (id: number | undefined, slug: string | undefined) => { + if (handleClose) { + handleClose() + dispatch(setCategoryId(id)) + dispatch(setCategorySlug(slug)) + } + } + return ( <> {isCatalog && ( @@ -40,7 +54,7 @@ const HeaderMenuModalCatalog: FC = ({
  • handleCloseAndDispatch(item.id, item.slug)} className={styles.headerMenuModalCatalog__route}> {item.name} diff --git a/src/widgets/ProductItem/CardPreview/CardPreview.module.scss b/src/features/ProductItem/CardPreview/CardPreview.module.scss similarity index 91% rename from src/widgets/ProductItem/CardPreview/CardPreview.module.scss rename to src/features/ProductItem/CardPreview/CardPreview.module.scss index b76a7f04..3578d672 100644 --- a/src/widgets/ProductItem/CardPreview/CardPreview.module.scss +++ b/src/features/ProductItem/CardPreview/CardPreview.module.scss @@ -1,4 +1,4 @@ -@use '../../../shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/variables' as var; .modal-card { margin: 0 50px; @@ -61,7 +61,8 @@ svg { width: 25px; - height: 20px; + min-width: 25px; + height: 25px; } } diff --git a/src/widgets/ProductItem/CardPreview/CardPreview.tsx b/src/features/ProductItem/CardPreview/CardPreview.tsx similarity index 88% rename from src/widgets/ProductItem/CardPreview/CardPreview.tsx rename to src/features/ProductItem/CardPreview/CardPreview.tsx index e2c9a5ba..c204d1dc 100644 --- a/src/widgets/ProductItem/CardPreview/CardPreview.tsx +++ b/src/features/ProductItem/CardPreview/CardPreview.tsx @@ -2,12 +2,13 @@ import { type FC, lazy, useState, Suspense } from 'react' import { useNavigate } from 'react-router-dom' import IconCart from '@/assets/icons/IconCart.svg' +import WB from '@/assets/icons/WB.svg' import { useProductInCart } from '@/entities/CartEntity/model/hooks/cartHooks' import { useWithFavorite } from '@/entities/Favorite/model/hooks/useWithFavorie' +import { ProductAvailability } from '@/entities/ProductAvailability/ProductAvailability' +import { ProductImgCarousel } from '@/entities/ProductImgCarousel/ProductImgCarousel' import { CardPreviewFooter } from '@/features/CardPreviewFooter/CardPreviewFooter' import { CardPreviewHeader } from '@/features/CardPreviewHeader/CardPreviewHeader' -import { ProductAvailability } from '@/features/ProductAvailability/ProductAvailability' -import { ProductImgCarousel } from '@/features/ProductImgCarousel/ProductImgCarousel' import { Routes } from '@/shared/config/routerConfig/routes' import { IProduct } from '@/shared/model/types/ProductModel' import { Button, ButtonSize, ButtonTheme } from '@/shared/ui/Button/Button' @@ -18,7 +19,7 @@ import { PopupImg } from '@/widgets/Product/ui/PopupImg/PopupImg' import styles from './CardPreview.module.scss' -const LazyQuickPurchaseForm = lazy(() => import('@/features/QuickPurchase/index')) +const LazyQuickPurchaseForm = lazy(() => import('@/features/QuickPurchase')) type TProps = | 'name' @@ -32,6 +33,7 @@ type TProps = | 'label_popular' | 'quantity' | 'id' + | 'wb_urls' type TCardPreviewProps = Pick @@ -48,6 +50,7 @@ type TCardPreviewProps = Pick * @param {boolean} label_hit - лейбл Хит на товаре; * @param {number} quantity - количество на склаладе (если > 0, то товар считается в наличии); * @param {number} id - id товара в backend; + * @param {string} wb_urls - ссылка на товар на wb */ export const CardPreview: FC = ({ name, @@ -60,7 +63,8 @@ export const CardPreview: FC = ({ label_popular, label_hit, quantity, - id + id, + wb_urls }) => { const navigate = useNavigate() const { isInCart, handleAddToCart } = useProductInCart(slug, id) @@ -71,7 +75,7 @@ export const CardPreview: FC = ({ const { isLiked, handleLike } = useWithFavorite({ id, category: '', - wb_urls: '', + wb_urls, is_deleted: false, wholesale: 0, name, @@ -102,6 +106,10 @@ export const CardPreview: FC = ({ setIsModalOpen(!isModalOpen) } + const buyWBHandle = () => { + window.open(wb_urls, '_blank') + } + return ( <> {isModalOpen && ( @@ -118,9 +126,6 @@ export const CardPreview: FC = ({
    {showPopup && } - {/* /!* @TODO: Добавить компонент для фотографии товара*/} - {/*https://github.com/Studio-Yandex-Practicum/maxboom_frontend/issues/41 *!/*/} - {/* {name}*/}
    = ({ {isInCart ? 'Перейти в корзину' : 'Купить'} + {wb_urls && ( + + )} diff --git a/src/widgets/ProductItem/CardPreview/CardPrewiew.stories.tsx b/src/features/ProductItem/CardPreview/CardPrewiew.stories.tsx similarity index 95% rename from src/widgets/ProductItem/CardPreview/CardPrewiew.stories.tsx rename to src/features/ProductItem/CardPreview/CardPrewiew.stories.tsx index 7bf8de51..51f081c3 100644 --- a/src/widgets/ProductItem/CardPreview/CardPrewiew.stories.tsx +++ b/src/features/ProductItem/CardPreview/CardPrewiew.stories.tsx @@ -1,7 +1,7 @@ import { Meta, StoryObj } from '@storybook/react' import image1 from '@/assets/images/product/1-260x260.webp' -import { CardPreview } from '@/widgets/ProductItem/CardPreview/CardPreview' +import { CardPreview } from '@/features/ProductItem/CardPreview/CardPreview' const meta = { title: 'widgets/CardPreview', diff --git a/src/widgets/ProductItem/ProductItem.module.scss b/src/features/ProductItem/ProductItem.module.scss similarity index 97% rename from src/widgets/ProductItem/ProductItem.module.scss rename to src/features/ProductItem/ProductItem.module.scss index fb26c90c..cb8d8794 100644 --- a/src/widgets/ProductItem/ProductItem.module.scss +++ b/src/features/ProductItem/ProductItem.module.scss @@ -1,4 +1,4 @@ -@use '../../shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/variables' as var; .product-item { position: relative; diff --git a/src/widgets/ProductItem/ProductItem.stories.tsx b/src/features/ProductItem/ProductItem.stories.tsx similarity index 96% rename from src/widgets/ProductItem/ProductItem.stories.tsx rename to src/features/ProductItem/ProductItem.stories.tsx index 2955d5cd..b61b6cc5 100644 --- a/src/widgets/ProductItem/ProductItem.stories.tsx +++ b/src/features/ProductItem/ProductItem.stories.tsx @@ -5,9 +5,9 @@ import image2 from '@/assets/images/product/1-500x500.webp' import image3 from '@/assets/images/product/2-500x500.webp' import image4 from '@/assets/images/product/3-500x500.webp' import image5 from '@/assets/images/product/4-500x500.webp' +import { ProductItem } from '@/features/ProductItem/ProductItem' import { ECardView } from '@/shared/model/types/common' import type { IProduct } from '@/shared/model/types/ProductModel' -import { ProductItem } from '@/widgets/ProductItem/ProductItem' export default { title: 'widgets/ProductItem', diff --git a/src/widgets/ProductItem/ProductItem.tsx b/src/features/ProductItem/ProductItem.tsx similarity index 86% rename from src/widgets/ProductItem/ProductItem.tsx rename to src/features/ProductItem/ProductItem.tsx index 329b791d..a8e3f0a0 100644 --- a/src/widgets/ProductItem/ProductItem.tsx +++ b/src/features/ProductItem/ProductItem.tsx @@ -2,11 +2,13 @@ import classnames from 'classnames' import { type FC, useState } from 'react' import { Link } from 'react-router-dom' +import Carousel from '@/entities/Carousel/Carousel' import { useProductInCart } from '@/entities/CartEntity/model/hooks/cartHooks' import { useWithFavorite } from '@/entities/Favorite/model/hooks/useWithFavorie' -import { ProductAvailability } from '@/features/ProductAvailability/ProductAvailability' -import { WidgetButtonsFunctions } from '@/features/WidgetButtonsFunctions/WidgetButtonsFunctions' -import { WidgetButtonsPurchase } from '@/features/WidgetButtonsPurchase/WidgetButtonsPurchase' +import { ProductAvailability } from '@/entities/ProductAvailability/ProductAvailability' +import { WidgetButtonsFunctions } from '@/entities/WidgetButtonsFunctions/WidgetButtonsFunctions' +import { WidgetButtonsPurchase } from '@/entities/WidgetButtonsPurchase/WidgetButtonsPurchase' +import { CardPreview } from '@/features/ProductItem/CardPreview/CardPreview' import { Routes } from '@/shared/config/routerConfig/routes' import { handleCutDescription } from '@/shared/libs/helpers/handleCutDescription' import { ECardView } from '@/shared/model/types/common' @@ -16,8 +18,6 @@ import Modal from '@/shared/ui/Modal/Modal' import Paragraph from '@/shared/ui/Paragraph/Paragraph' import { ProductLabels } from '@/shared/ui/ProductLabels/ProductLabels' import { getStylesForCurrentLayout } from '@/shared/ui/ProductLabels/utils/utils' -import Carousel from '@/widgets/Carousel/Carousel' -import { CardPreview } from '@/widgets/ProductItem/CardPreview/CardPreview' import styles from './ProductItem.module.scss' @@ -39,6 +39,7 @@ interface IProductCardProps extends IProduct { * @param {boolean} label_hit лейбл Хит на товаре; * @param {number} quantity количество на склаладе (если > 0, то товар считается в наличии); * @param {number} id id товара в backend; + * @param {string} wb_urls ссылка на страницу с товаром на wb */ export const ProductItem: FC = ({ layout, @@ -52,7 +53,8 @@ export const ProductItem: FC = ({ label_popular, label_hit, quantity, - id + id, + wb_urls }) => { const [isInCompared, setIsInCompared] = useState(false) const [isModalOpen, setIsModalOpen] = useState(false) @@ -97,6 +99,7 @@ export const ProductItem: FC = ({ code={code} price={Number(price)} brand={brand} + wb_urls={wb_urls} slug={slug} images={images} quantity={Number(quantity)} @@ -168,17 +171,20 @@ export const ProductItem: FC = ({ })}> {price} ₽ {layout !== ECardView.COMPACT && ( -
    - -
    + <> +
    + +
    + )}
  • @@ -193,6 +199,7 @@ export const ProductItem: FC = ({ handleAddToCart={handleAddToCart} onEyeClick={changeModalState} layout={layout} + wb_urls={wb_urls} /> { return ( diff --git a/src/widgets/ProductItem/ProductSkeleton/ProductSkeleton.tsx b/src/features/ProductItem/ProductSkeleton/ProductSkeleton.tsx similarity index 100% rename from src/widgets/ProductItem/ProductSkeleton/ProductSkeleton.tsx rename to src/features/ProductItem/ProductSkeleton/ProductSkeleton.tsx diff --git a/src/features/login/ui/LoginForm/LoginForm.tsx b/src/features/login/ui/LoginForm/LoginForm.tsx index 47887843..0ad6da4c 100644 --- a/src/features/login/ui/LoginForm/LoginForm.tsx +++ b/src/features/login/ui/LoginForm/LoginForm.tsx @@ -1,9 +1,11 @@ import { ErrorMessage, Field, Form, Formik, FormikHelpers } from 'formik' import { FC } from 'react' import { useSelector } from 'react-redux' +import { useNavigate } from 'react-router' import IconClose from '@/assets/icons/iconHeaderMenuClose.svg' import { getErrorAuthStatus } from '@/features/login/model/selectors/getUserAuthStatus' +import { Routes } from '@/shared/config/routerConfig/routes' import { useAppDispatch } from '@/shared/libs/hooks/store' import { Button, ButtonSize, ButtonTheme } from '@/shared/ui/Button/Button' import Heading, { HeadingType } from '@/shared/ui/Heading/Heading' @@ -35,6 +37,7 @@ const LoginForm: FC = ({ isModalOpen, handleClose, onLogin }) => email: '', password: '' } + const navigate = useNavigate() const dispatch = useAppDispatch() const error = useSelector(getErrorAuthStatus) const handleSubmit = async (values: LoginAuthData, helpers: FormikHelpers) => { @@ -45,6 +48,10 @@ const LoginForm: FC = ({ isModalOpen, handleClose, onLogin }) => } } + const onRegistration = () => { + navigate(Routes.REGISTRATION) + } + return ( = ({ isModalOpen, handleClose, onLogin }) => disabled={!isValid || !dirty || isSubmitting}> Войти -
    diff --git a/src/mockData/blogMainItemData.ts b/src/mockData/blogMainItemData.ts index 41ad56b9..fcec9499 100644 --- a/src/mockData/blogMainItemData.ts +++ b/src/mockData/blogMainItemData.ts @@ -1,12 +1,12 @@ -import main from '@/assets/images/blogMainItem/img-article-02-1500x1000.webp.svg' +import image from '@/assets/images/blogMainItem/img-article-02-1500x1000.webp' export const blogMainItemData = { id: 1, - src: main, + src: image, alt: 'Дайджест интересных материалов для мобильного разработчика', title: 'Дайджест интересных материалов для мобильного разработчика', date: '8 Мая, 2022', - tags: ['#дорога', '#путешествия', '#экономика'], + tags: ['дорога', 'путешествия', 'экономика'], category: 'Обзоры', comments: ['', ''] } diff --git a/src/mockData/headerMenuData.ts b/src/mockData/headerMenuData.ts index dafcda69..4edeaf1a 100644 --- a/src/mockData/headerMenuData.ts +++ b/src/mockData/headerMenuData.ts @@ -21,7 +21,7 @@ export const headerMenuData = [ }, { title: 'Отзывы о магазине', - link: Routes.REVIEWS + link: Routes.FEEDBACKS }, { title: 'Контакты', diff --git a/src/models/PropsBlog.ts b/src/models/PropsBlog.ts deleted file mode 100644 index 897232ed..00000000 --- a/src/models/PropsBlog.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { TBlogItem } from './BlogItemModel' - -export type PropsBlog = { - title?: string - linkText?: string - linkPath?: string - cards: TBlogItem[] -} - -export type PropsCategories = { - title?: string - linkText?: string - linkPath?: string - cards: TBlogItem[] - filterItems: (curcat?: string) => void -} - -export type PropsTags = { - title?: string - linkText?: string - linkPath?: string - cards: TBlogItem[] - filterItems: (curcat: string) => void -} - -export type ObjectType = { - name: string -} diff --git a/src/pages/AboutUsPage/AboutUsPage.tsx b/src/pages/AboutUsPage/AboutUsPage.tsx index 375d4288..75e68940 100644 --- a/src/pages/AboutUsPage/AboutUsPage.tsx +++ b/src/pages/AboutUsPage/AboutUsPage.tsx @@ -1,11 +1,11 @@ import { useEffect } from 'react' import { useSelector } from 'react-redux' -import WrapperForMainContent from '@/components/WrapperForMainContent/WrapperForMainContent' import AboutUs from '@/entities/AboutUs' import { useAppDispatch } from '@/shared/libs/hooks/store' import Breadcrumbs from '@/shared/ui/Breadcrumbs/Breadcrumbs' import Heading, { HeadingType } from '@/shared/ui/Heading/Heading' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' import styles from './AboutUsPage.module.scss' import { getAboutUsSelector } from './model/selectors/selectors' diff --git a/src/pages/AccountPage/AccountPage.tsx b/src/pages/AccountPage/AccountPage.tsx index 24f51d56..2230058d 100644 --- a/src/pages/AccountPage/AccountPage.tsx +++ b/src/pages/AccountPage/AccountPage.tsx @@ -1,12 +1,12 @@ import { type FC, Suspense, useState } from 'react' -import WrapperForMainContent from '@/components/WrapperForMainContent/WrapperForMainContent' import SideBarMenuModal from '@/features/SideBarMenuModal' import { useResize } from '@/shared/libs/hooks/useResize' import Breadcrumbs from '@/shared/ui/Breadcrumbs/Breadcrumbs' import Heading from '@/shared/ui/Heading/Heading' import Modal from '@/shared/ui/Modal/Modal' import Spinner from '@/shared/ui/Spinner/Spinner' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' import { AccountCart } from '@/widgets/AccountCart/AccountCart' import { AccountMenu } from '@/widgets/AccountMenu/AccountMenu' import { AccountSubscribe } from '@/widgets/AccountSubscribe/AccountSubscribe' diff --git a/src/pages/BlogPage/BlogPage.tsx b/src/pages/BlogPage/BlogPage.tsx index 719678db..b413f0af 100644 --- a/src/pages/BlogPage/BlogPage.tsx +++ b/src/pages/BlogPage/BlogPage.tsx @@ -1,12 +1,36 @@ -import BlogMain from '@/components/BlogMain/BlogMain' -import WrapperForMainContent from '@/components/WrapperForMainContent/WrapperForMainContent' -import { blogPageData } from '@/mockData/blogPageData' -import { TEXT_BLOG, LINK_SHOW_ALL } from '@/shared/constants/constants' +import { FC } from 'react' -const BlogPage = () => { +import { Routes } from '@/shared/config/routerConfig/routes' +import { TEXT_BLOG } from '@/shared/constants/constants' +import Breadcrumbs from '@/shared/ui/Breadcrumbs/Breadcrumbs' +import Heading, { HeadingType } from '@/shared/ui/Heading/Heading' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' +import BlogMain from '@/widgets/BlogMain' +import SideBarBlog from '@/widgets/SideBarBlog' + +import styles from './blog.module.scss' + +const links = [ + { heading: 'Главная', href: Routes.HOME }, + { heading: 'Блог', href: '' } +] + +/** + * Страница - Блог + */ + +const BlogPage: FC = () => { return ( - +
    + {TEXT_BLOG} + +
    + +
    + + +
    ) } diff --git a/src/pages/BlogPage/blog.module.scss b/src/pages/BlogPage/blog.module.scss index 8d94915e..6b501772 100644 --- a/src/pages/BlogPage/blog.module.scss +++ b/src/pages/BlogPage/blog.module.scss @@ -1,15 +1,20 @@ -.blog { +@use '@/shared/styles/utils/mixins' as media; + +.titleBox { display: flex; flex-direction: column; - gap: 60px; + gap: 10px; + width: 100%; +} + +.blogPage { + display: flex; + gap: 20px; + width: 100%; + margin-top: -18px; - &__wrapper { - max-width: 1080px; - display: grid; - grid-template-columns: repeat(auto-fit, minmax(360px, 1fr)); - grid-template-rows: auto; - row-gap: 20px; - column-gap: 20px; - justify-content: center; + @include media.respond-to('large') { + flex-direction: column; + gap: 10px; } } diff --git a/src/pages/CartPage/CartPage.module.scss b/src/pages/CartPage/CartPage.module.scss index a942fbb7..887146bc 100644 --- a/src/pages/CartPage/CartPage.module.scss +++ b/src/pages/CartPage/CartPage.module.scss @@ -1,9 +1,21 @@ -@use '../../shared/styles/utils/variables' as var; -@use '../../shared/styles/utils/mixins' as media; +@use '@/shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/mixins' as media; + +.titleBox { + display: flex; + flex-direction: column; + gap: 10px; + width: 100%; +} + +.heading { + padding-top: 20px; +} .container { display: flex; column-gap: 20px; + margin-top: -18px; margin-bottom: 160px; width: 100%; @@ -26,10 +38,6 @@ row-gap: 10px; } -.heading { - margin-top: 20px; -} - .titles { display: flex; flex-direction: column; diff --git a/src/pages/CartPage/CartPage.tsx b/src/pages/CartPage/CartPage.tsx index 6852ca0d..b25ce2b9 100644 --- a/src/pages/CartPage/CartPage.tsx +++ b/src/pages/CartPage/CartPage.tsx @@ -1,17 +1,22 @@ import { useSelector } from 'react-redux' -import { Link } from 'react-router-dom' -import WrapperForMainContent from '@/components/WrapperForMainContent/WrapperForMainContent' import { getCartSelector } from '@/entities/CartEntity/model/selectors/selectors' import type { ICartEntity } from '@/entities/CartEntity/model/types/types' import { CartCouponApply } from '@/features/CartCouponApply/ui/CartCouponApply/CartCouponApply' import { CartEdit } from '@/features/CartEdit/ui/CartEdit/CartEdit' +import { Routes } from '@/shared/config/routerConfig/routes' +import Breadcrumbs from '@/shared/ui/Breadcrumbs/Breadcrumbs' import Heading, { HeadingType } from '@/shared/ui/Heading/Heading' -import Subheading from '@/shared/ui/Subheading/Subheading' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' import { MakeOrder } from '@/widgets/MakeOrder/ui/MakeOrder/MakeOrder' import styles from './CartPage.module.scss' +const links = [ + { heading: 'Главная', href: Routes.HOME }, + { heading: 'Корзина покупок', href: '' } +] + /** * Компонент страница корзины. На странице отображаются товары в корзине, можно изменять кол-во товаров в корзине, * сразу происходит изменение стоимости. Также можно добавить сертификат или купон на скидку, есть опция оформения быстрого и обычного заказа @@ -21,27 +26,21 @@ const CartPage = () => { return ( -
    - - Оформление заказа ({cart.cart_full_weight.toFixed(2)} кг) - {/* Кг приходит с бека или нет, tbd */} - - - - Главная - {' '} - / Корзина покупок - - +
    + Оформление заказа ({cart.cart_full_weight.toFixed(2)} кг) + + Ваши покупки -
    + +
    -
    - {cart.products.map(item => { - return - })} -
    +
      + {cart.products.map(item => ( + + ))} +
    +
    total + item.amount, 0)} diff --git a/src/pages/CategoryPage/CategoryPage.module.scss b/src/pages/CategoryPage/CategoryPage.module.scss index 8115ba6c..73cdb92c 100644 --- a/src/pages/CategoryPage/CategoryPage.module.scss +++ b/src/pages/CategoryPage/CategoryPage.module.scss @@ -2,12 +2,13 @@ .category-page { width: 100%; - margin-left: 15px; } .category-page__title { margin-top: 24px; margin-bottom: 10px; + font-size: 25px; + line-height: 1.15; } .category-page__nav { @@ -17,5 +18,8 @@ } .category-page__subtiitle { - margin-bottom: 30px; + margin: 30px 0; + color: var.$black; + font-size: 20px; + line-height: 1.15; } diff --git a/src/pages/CategoryPage/CategoryPage.tsx b/src/pages/CategoryPage/CategoryPage.tsx index a6321779..1aeb47e1 100644 --- a/src/pages/CategoryPage/CategoryPage.tsx +++ b/src/pages/CategoryPage/CategoryPage.tsx @@ -1,24 +1,28 @@ +import Breadcrumbs from '@/shared/ui/Breadcrumbs/Breadcrumbs' import Heading from '@/shared/ui/Heading/Heading' -import Paragraph from '@/shared/ui/Paragraph/Paragraph' +import Subheading from '@/shared/ui/Subheading/Subheading' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' import CategoryCardList from '@/widgets/CategoryCardList/CategoryCardList' -import NavigationLink from '@/widgets/NavigationLink/NavigationLink' import styles from './CategoryPage.module.scss' +const links = [ + { heading: 'Главная', href: '/' }, + { heading: 'Все категории', href: '' } +] + /** * Страница всех категорий */ - export const CategoryPage = () => { return ( -
    - Все категории -
    - - / Все категории + +
    + Все категории + + Категории +
    - Категории - -
    + ) } diff --git a/src/pages/ComparePage/ComparePage.tsx b/src/pages/ComparePage/ComparePage.tsx index 5a6cbf87..65820dd1 100644 --- a/src/pages/ComparePage/ComparePage.tsx +++ b/src/pages/ComparePage/ComparePage.tsx @@ -1,6 +1,6 @@ -import WrapperForMainContent from '@/components/WrapperForMainContent/WrapperForMainContent' import Heading from '@/shared/ui/Heading/Heading' import Subheading from '@/shared/ui/Subheading/Subheading' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' import styles from './ComparePage.module.scss' diff --git a/src/pages/ContactsPage/ContactsPage.tsx b/src/pages/ContactsPage/ContactsPage.tsx index 4e423797..41bd4922 100644 --- a/src/pages/ContactsPage/ContactsPage.tsx +++ b/src/pages/ContactsPage/ContactsPage.tsx @@ -5,6 +5,8 @@ import YMap from '@/assets/icons/YMap.svg' import FormQuestion from '@/features/FormQuestion/ui/FormQuestion' import Breadcrumbs from '@/shared/ui/Breadcrumbs/Breadcrumbs' import Heading, { HeadingType } from '@/shared/ui/Heading/Heading' +import Paragraph from '@/shared/ui/Paragraph/Paragraph' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' import Map from '@/widgets/Map/Map' import styles from './ContactsPage.module.scss' @@ -16,69 +18,99 @@ const links = [ const ContactsPage: FC = () => { return ( -
    -
    - Контакты - -
    - -
    -
    - Основной магазин -
      -
    • Телефон
    • -
    • +7 977 848-02-28
    • -
    • Будни, с 10.00 до 20.00
    • -
    -
      -
    • Электронная почта
    • - - Maxboomofficial@yandex.ru - -
    -
      -
    • Адрес магазина
    • - - - г. Москва - -
    + +
    +
    + Контакты +
    -
    - Наши реквизиты -
    -

    Банковские и юридические реквизиты

    -
    -
      -
    • Наименование
    • -
    • Maxboom.ru
    • -
    -
    -
    -
    + +
    +
    + Основной магазин +
      +
    • + Телефон +
    • +
    • + +7 977 848-02-28 +
    • +
    • + Будни, с 10.00 до 20.00 +
    • +
      -
    • ОГРН
    • -
    • 123456789
    • +
    • + Электронная почта +
    • + + Maxboomofficial@yandex.ru +
      -
    • Адрес
    • -
    • 104329, Москва г, Талалихина
    • -
    • ул, дом № 1, корпус 3, оф.8
    • +
    • + Адрес магазина{' '} +
    • + + + г. Москва +
    -
    -
      -
    • Телефон
    • -
    • +7 977 848-02-28
    • +
      + Наши реквизиты +
      + Банковские и юридические реквизиты +
      +
        +
      • + Наименование +
      • +
      • + Maxboom.ru +
      +
      +
      +
        +
      • + ОГРН +
      • +
      • + 123456789 +
      • +
      +
        +
      • + Адрес +
      • +
      • + + {`104329, Москва г, Талалихина + ул, дом № 1, корпус 3, оф.8`} + +
      • +
      +
      +
      +
        +
      • + Телефон +
      • +
      • + +7 977 848-02-28 +
      • +
      +
      +
      +
    - -
    -
    +
    + ) } diff --git a/src/pages/DeliveryPage/DeliveryPage.tsx b/src/pages/DeliveryPage/DeliveryPage.tsx index 8abdd721..293beb56 100644 --- a/src/pages/DeliveryPage/DeliveryPage.tsx +++ b/src/pages/DeliveryPage/DeliveryPage.tsx @@ -1,6 +1,6 @@ -import WrapperForMainContent from '@/components/WrapperForMainContent/WrapperForMainContent' import Breadcrumbs from '@/shared/ui/Breadcrumbs/Breadcrumbs' import Heading, { HeadingType } from '@/shared/ui/Heading/Heading' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' import styles from './DeliveryPage.module.scss' diff --git a/src/pages/ErrorPage/ErrorPage.tsx b/src/pages/ErrorPage/ErrorPage.tsx index 828f1b80..46c8af14 100644 --- a/src/pages/ErrorPage/ErrorPage.tsx +++ b/src/pages/ErrorPage/ErrorPage.tsx @@ -1,11 +1,11 @@ import { FC } from 'react' import image from '@/assets/images/errorPage/img-page-not-found.webp' -import WrapperForMainContent from '@/components/WrapperForMainContent/WrapperForMainContent' import { Routes } from '@/shared/config/routerConfig/routes' import Heading, { HeadingType } from '@/shared/ui/Heading/Heading' import Link from '@/shared/ui/Link/Link' import Paragraph from '@/shared/ui/Paragraph/Paragraph' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' import styles from './ErrorPage.module.scss' diff --git a/src/pages/FavoritesPage/FavoritesPage.tsx b/src/pages/FavoritesPage/FavoritesPage.tsx index e913b8ff..284e60a0 100644 --- a/src/pages/FavoritesPage/FavoritesPage.tsx +++ b/src/pages/FavoritesPage/FavoritesPage.tsx @@ -1,6 +1,5 @@ import { FC, Suspense, useState } from 'react' -import WrapperForMainContent from '@/components/WrapperForMainContent/WrapperForMainContent' import { useFavorite } from '@/entities/Favorite/model/hooks/useFavorite' import SideBarMenuModal from '@/features/SideBarMenuModal' import { Routes } from '@/shared/config/routerConfig/routes' @@ -10,6 +9,7 @@ import Breadcrumbs from '@/shared/ui/Breadcrumbs/Breadcrumbs' import Heading from '@/shared/ui/Heading/Heading' import Modal from '@/shared/ui/Modal/Modal' import Spinner from '@/shared/ui/Spinner/Spinner' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' import { ProductsList } from '@/widgets/ProductsList/ProductsList' import { withAdaptiveSideBar } from '@/widgets/SideBarMenu' diff --git a/src/pages/FeedbackPage/FeedbackPage.tsx b/src/pages/FeedbackPage/FeedbackPage.tsx index 03651c2c..ebaead36 100644 --- a/src/pages/FeedbackPage/FeedbackPage.tsx +++ b/src/pages/FeedbackPage/FeedbackPage.tsx @@ -3,18 +3,19 @@ import { useSelector } from 'react-redux' import { useParams } from 'react-router' import { StateSchema } from '@/app/providers/StoreProvider' -import WrapperForMainContent from '@/components/WrapperForMainContent/WrapperForMainContent' import { getAverageMark, getFirstFeedbacks, getNextFeedbacks } from '@/features/Reviews/model/slice/feedbacksSlice' import { bodyScrollControl } from '@/shared/libs/helpers/popupHelper' +import { scrollPageToTop } from '@/shared/libs/helpers/scrollPageToTop' import { useAppDispatch } from '@/shared/libs/hooks/store' import { useResize } from '@/shared/libs/hooks/useResize' import Breadcrumbs from '@/shared/ui/Breadcrumbs/Breadcrumbs' import { Button, ButtonSize, ButtonTheme } from '@/shared/ui/Button/Button' import Heading from '@/shared/ui/Heading/Heading' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' import { AveregeMark } from '@/widgets/AveregeMark/AveregeMark' import { FeedbackForm } from '@/widgets/FeedbackForm/FeedbackForm' import { FeedbackList } from '@/widgets/FeedbackList/FeedbackList' @@ -42,6 +43,8 @@ export const FeedbackPage = () => { dispatch(getFirstFeedbacks()) dispatch(getAverageMark()) + + scrollPageToTop() }, []) const fetchNextPage = () => { @@ -63,7 +66,7 @@ export const FeedbackPage = () => {
    { diff --git a/src/pages/LoginPage/LoginPage.tsx b/src/pages/LoginPage/LoginPage.tsx index db9c1981..30334417 100644 --- a/src/pages/LoginPage/LoginPage.tsx +++ b/src/pages/LoginPage/LoginPage.tsx @@ -1,10 +1,10 @@ import { Suspense, lazy, useCallback } from 'react' import { useNavigate } from 'react-router' -import WrapperForMainContent from '@/components/WrapperForMainContent/WrapperForMainContent' import { Routes } from '@/shared/config/routerConfig/routes' import Heading from '@/shared/ui/Heading/Heading' import Spinner from '@/shared/ui/Spinner/Spinner' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' import styles from './LoginPage.module.scss' diff --git a/src/pages/LogoutPage/LogoutPage.tsx b/src/pages/LogoutPage/LogoutPage.tsx index 714949f7..b3ba9d9b 100644 --- a/src/pages/LogoutPage/LogoutPage.tsx +++ b/src/pages/LogoutPage/LogoutPage.tsx @@ -2,7 +2,6 @@ import { FC, Suspense, useMemo, useState } from 'react' import { useSelector } from 'react-redux' import { useNavigate } from 'react-router' -import WrapperForMainContent from '@/components/WrapperForMainContent/WrapperForMainContent' import { getUserAuthStatus } from '@/features/login/model/selectors/getUserAuthStatus' import SideBarMenuModal from '@/features/SideBarMenuModal' import { Routes } from '@/shared/config/routerConfig/routes' @@ -13,6 +12,7 @@ import Heading from '@/shared/ui/Heading/Heading' import Modal from '@/shared/ui/Modal/Modal' import Paragraph from '@/shared/ui/Paragraph/Paragraph' import Spinner from '@/shared/ui/Spinner/Spinner' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' import { withAdaptiveSideBar } from '@/widgets/SideBarMenu' import styles from './LogoutPage.module.scss' diff --git a/src/pages/MainPage/MainPage.tsx b/src/pages/MainPage/MainPage.tsx index 4d080d2a..ce4801c9 100644 --- a/src/pages/MainPage/MainPage.tsx +++ b/src/pages/MainPage/MainPage.tsx @@ -1,6 +1,6 @@ import { FC } from 'react' -import WrapperForMainContent from '@/components/WrapperForMainContent/WrapperForMainContent' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' import Advantages from '@/widgets/Advantages' import ArticleBlock from '@/widgets/ArticleBlock' import BannerBlock from '@/widgets/BannerBlock' diff --git a/src/pages/PrivacyPage/PrivacyPage.module.scss b/src/pages/PrivacyPage/PrivacyPage.module.scss new file mode 100644 index 00000000..9e09ffb7 --- /dev/null +++ b/src/pages/PrivacyPage/PrivacyPage.module.scss @@ -0,0 +1,27 @@ +@use '../../shared/styles/utils/mixins' as media; + +.privacyPage { + width: 100%; + display: flex; + flex-direction: column; + align-items: flex-start; + + &__pageDescriptor { + width: 100%; + display: flex; + flex-direction: column; + gap: 10px; + } + + &__contant { + margin-top: 40px; + width: 100%; + display: flex; + align-items: flex-start; + gap: 25px; + + @include media.respond-to('large') { + flex-direction: column-reverse; + } + } +} diff --git a/src/pages/PrivacyPage/PrivacyPage.tsx b/src/pages/PrivacyPage/PrivacyPage.tsx new file mode 100644 index 00000000..05e1c6af --- /dev/null +++ b/src/pages/PrivacyPage/PrivacyPage.tsx @@ -0,0 +1,33 @@ +import { FC } from 'react' + +import Breadcrumbs from '@/shared/ui/Breadcrumbs/Breadcrumbs' +import Heading from '@/shared/ui/Heading/Heading' +import Paragraph from '@/shared/ui/Paragraph/Paragraph' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' + +import styles from './PrivacyPage.module.scss' + +/** + * Страница с политикой безопасности. + * TODO наполнить страницу смыслом + */ +export const PrivacyPage: FC = () => { + const links = [ + { heading: 'Главная', href: '/' }, + { heading: 'Политика безопасности', href: '' } + ] + + return ( + +
    +
    + Политика безопасности + +
    +
    + Политика безопасности +
    +
    +
    + ) +} diff --git a/src/pages/ProductPage/ProductPage.tsx b/src/pages/ProductPage/ProductPage.tsx index 20566765..c1289efb 100644 --- a/src/pages/ProductPage/ProductPage.tsx +++ b/src/pages/ProductPage/ProductPage.tsx @@ -3,10 +3,11 @@ import { useSelector } from 'react-redux' import { useParams } from 'react-router' import { StateSchema } from '@/app/providers/StoreProvider' -import WrapperForMainContent from '@/components/WrapperForMainContent/WrapperForMainContent' +import { scrollPageToTop } from '@/shared/libs/helpers/scrollPageToTop' import { useAppDispatch } from '@/shared/libs/hooks/store' import Breadcrumbs from '@/shared/ui/Breadcrumbs/Breadcrumbs' import Heading from '@/shared/ui/Heading/Heading' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' import Advantages from '@/widgets/Advantages' import { Product } from '@/widgets/Product/Product' import { ProductInfo } from '@/widgets/ProductInfo/ProductInfo' @@ -31,6 +32,8 @@ export const ProductPage = () => { ] useEffect(() => { + scrollPageToTop() + if (slug) dispatch(getProduct(slug)) }, [slug]) diff --git a/src/pages/ProductsPage/ProductsPage.module.scss b/src/pages/ProductsPage/ProductsPage.module.scss index 3fb6e11c..7639fac7 100644 --- a/src/pages/ProductsPage/ProductsPage.module.scss +++ b/src/pages/ProductsPage/ProductsPage.module.scss @@ -1,4 +1,5 @@ -@use '../../shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/mixins' as media; .content-grid { width: 100%; @@ -18,4 +19,30 @@ display: flex; flex-wrap: wrap; gap: 30px; + + @include media.respond-to('large') { + margin: auto; + justify-content: center; + } +} + +.mobileInvisible { + height: fit-content; + max-width: 330px; + + @include media.respond-to('large') { + display: none; + } +} + +.mobile-page-controls{ + display: flex; + width: 100%; + align-items: end; + + @include media.respond-to('middle') { + flex-direction: column; + align-items: flex-start; + gap: 10px; + } } diff --git a/src/pages/ProductsPage/ProductsPage.tsx b/src/pages/ProductsPage/ProductsPage.tsx index fad3dcdd..fa0a3362 100644 --- a/src/pages/ProductsPage/ProductsPage.tsx +++ b/src/pages/ProductsPage/ProductsPage.tsx @@ -4,27 +4,29 @@ import { useSelector } from 'react-redux' import { useLocation } from 'react-router' import { useNavigate } from 'react-router-dom' -import { selectFilterProducts, selectFilterQuantity } from '@/components/Dropdown/selectors/selectors' -import { setFilterProducts, setProductQuantityFilter } from '@/components/Dropdown/slice/filtersSlice' -import { PageControls } from '@/components/PageControls/PageControls' -import { PageControlsSkeletons } from '@/components/PageControls/PageControlsSkeletons/PageControlsSkeletons' -import { PageDescription } from '@/components/PageDescription/PageDescription' -import { PageDescriptionSkeleton } from '@/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton' -import { Pagination } from '@/components/Pagination/Pagination' -import { selectNumberOfPage } from '@/components/Pagination/selectors/selectors' -import { setNumberOfPage } from '@/components/Pagination/slice/paginationSlice' -import WrapperForMainContent from '@/components/WrapperForMainContent/WrapperForMainContent' import { selectCategoryId, selectCategorySlug } from '@/entities/Category/selectors/categorySelectors' import { setCategoryId } from '@/entities/Category/slice/categoryIdSlice' +import { ProductSkeleton } from '@/features/ProductItem/ProductSkeleton/ProductSkeleton' import { getLoading, getProductsOfCategorySelector } from '@/pages/ProductsPage/selectors/selectors' import { getProducts } from '@/pages/ProductsPage/services/getProducts' import { ITEMS_PER_PAGE_OPTION, NUMBER_OF_PRODUCTS, SORT_OPTION } from '@/shared/constants/constants' +import { scrollPageToTop } from '@/shared/libs/helpers/scrollPageToTop' import { totalPagesHandler } from '@/shared/libs/helpers/totalPagesHandler' import { useAppDispatch } from '@/shared/libs/hooks/store' import { useReplaceValueFromLocation } from '@/shared/libs/hooks/useReplaceValueFromLocation' import { ECardView } from '@/shared/model/types/common' +import { selectFilterProducts, selectFilterQuantity } from '@/shared/ui/Dropdown/selectors/selectors' +import { setFilterProducts, setProductQuantityFilter } from '@/shared/ui/Dropdown/slice/filtersSlice' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' import { CategoryList } from '@/widgets/CategoryList/CategoryList' -import { ProductSkeleton } from '@/widgets/ProductItem/ProductSkeleton/ProductSkeleton' +import { CategoryListMobilePopup } from '@/widgets/CategoryList/CategoryListMobilePopup/CategoryListMobilePopup' +import { PageControls } from '@/widgets/PageControls/PageControls' +import { PageControlsSkeletons } from '@/widgets/PageControls/PageControlsSkeletons/PageControlsSkeletons' +import { PageDescription } from '@/widgets/PageDescription/PageDescription' +import { PageDescriptionSkeleton } from '@/widgets/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton' +import { Pagination } from '@/widgets/Pagination/Pagination' +import { selectNumberOfPage } from '@/widgets/Pagination/selectors/selectors' +import { setNumberOfPage } from '@/widgets/Pagination/slice/paginationSlice' import { ProductsList } from '@/widgets/ProductsList/ProductsList' import styles from './ProductsPage.module.scss' @@ -100,6 +102,7 @@ export const ProductsPage = () => { } useEffect(() => { + scrollPageToTop() dispatch(getProducts({ categoryId, filterProducts, filterQuantity, productsQuantityPerPage })) }, [productsQuantityPerPage, categorySlug, filterProducts, filterQuantity, idOfCategory]) @@ -148,7 +151,7 @@ export const ProductsPage = () => { )}
    - +
    {isLoading ? ( @@ -162,16 +165,19 @@ export const ProductsPage = () => { ) : categoriesProducts.results.length > 0 ? ( <> - +
    + + +
    ) : ( diff --git a/src/pages/ReviewsPage/ReviewsPage.module.scss b/src/pages/ReviewsPage/ReviewsPage.module.scss new file mode 100644 index 00000000..8bdcc4c7 --- /dev/null +++ b/src/pages/ReviewsPage/ReviewsPage.module.scss @@ -0,0 +1,27 @@ +@use '../../shared/styles/utils/mixins' as media; + +.reviewsPage { + width: 100%; + display: flex; + flex-direction: column; + align-items: flex-start; + + &__pageDescriptor { + width: 100%; + display: flex; + flex-direction: column; + gap: 10px; + } + + &__contant { + margin-top: 40px; + width: 100%; + display: flex; + align-items: flex-start; + gap: 25px; + + @include media.respond-to('large') { + flex-direction: column-reverse; + } + } +} diff --git a/src/pages/ReviewsPage/ReviewsPage.tsx b/src/pages/ReviewsPage/ReviewsPage.tsx new file mode 100644 index 00000000..fc3bc1e6 --- /dev/null +++ b/src/pages/ReviewsPage/ReviewsPage.tsx @@ -0,0 +1,35 @@ +import { FC } from 'react' + +import { Routes } from '@/shared/config/routerConfig/routes' +import Breadcrumbs from '@/shared/ui/Breadcrumbs/Breadcrumbs' +import Heading from '@/shared/ui/Heading/Heading' +import Paragraph from '@/shared/ui/Paragraph/Paragraph' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' + +import styles from './ReviewsPage.module.scss' + +/** + * Страница с обзорами. + * TODO наполнить страницу смыслом + */ +export const ReviewsPage: FC = () => { + const links = [ + { heading: 'Главная', href: '/' }, + { heading: 'Блог', href: Routes.BLOG }, + { heading: 'Обзоры', href: '' } + ] + + return ( + +
    +
    + Обзоры + +
    +
    + Обзоры +
    +
    +
    + ) +} diff --git a/src/pages/SearchResultsPage/SearchResultsPage.tsx b/src/pages/SearchResultsPage/SearchResultsPage.tsx index a1ec43cb..a5fe5b63 100644 --- a/src/pages/SearchResultsPage/SearchResultsPage.tsx +++ b/src/pages/SearchResultsPage/SearchResultsPage.tsx @@ -5,11 +5,11 @@ import { useParams } from 'react-router-dom' import { ThunkExtraArg } from '@/app/providers/StoreProvider/config/StateSchema' import { RootState } from '@/app/providers/StoreProvider/config/store' -import WrapperForMainContent from '@/components/WrapperForMainContent/WrapperForMainContent' import { selectSearchResult } from '@/features/SearchProduct/selectors/searchProductSelectors' import { search } from '@/features/SearchProduct/slice/searchProductSlice' import Heading from '@/shared/ui/Heading/Heading' import Subheading from '@/shared/ui/Subheading/Subheading' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' import styles from './SearchResultsPage.module.scss' diff --git a/src/pages/TermsPage/TermsPage.module.scss b/src/pages/TermsPage/TermsPage.module.scss new file mode 100644 index 00000000..69a55b2a --- /dev/null +++ b/src/pages/TermsPage/TermsPage.module.scss @@ -0,0 +1,27 @@ +@use '../../shared/styles/utils/mixins' as media; + +.termsPage { + width: 100%; + display: flex; + flex-direction: column; + align-items: flex-start; + + &__pageDescriptor { + width: 100%; + display: flex; + flex-direction: column; + gap: 10px; + } + + &__contant { + margin-top: 40px; + width: 100%; + display: flex; + align-items: flex-start; + gap: 25px; + + @include media.respond-to('large') { + flex-direction: column-reverse; + } + } +} diff --git a/src/pages/TermsPage/TermsPage.tsx b/src/pages/TermsPage/TermsPage.tsx new file mode 100644 index 00000000..8faaa8ab --- /dev/null +++ b/src/pages/TermsPage/TermsPage.tsx @@ -0,0 +1,33 @@ +import { FC } from 'react' + +import Breadcrumbs from '@/shared/ui/Breadcrumbs/Breadcrumbs' +import Heading from '@/shared/ui/Heading/Heading' +import Paragraph from '@/shared/ui/Paragraph/Paragraph' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' + +import styles from './TermsPage.module.scss' + +/** + * Страница с условиями соглашения. + * TODO наполнить страницу смыслом + */ +export const TermsPage: FC = () => { + const links = [ + { heading: 'Главная', href: '/' }, + { heading: 'Условия соглашения', href: '' } + ] + + return ( + +
    +
    + Условия соглашения + +
    +
    + Условия соглашения +
    +
    +
    + ) +} diff --git a/src/pages/VouchersPage/VouchersPage.tsx b/src/pages/VouchersPage/VouchersPage.tsx index 61dbbb31..8088f66c 100644 --- a/src/pages/VouchersPage/VouchersPage.tsx +++ b/src/pages/VouchersPage/VouchersPage.tsx @@ -1,5 +1,5 @@ -import WrapperForMainContent from '@/components/WrapperForMainContent/WrapperForMainContent' import Heading, { HeadingType } from '@/shared/ui/Heading/Heading' +import WrapperForMainContent from '@/shared/ui/WrapperForMainContent/WrapperForMainContent' import FormBuyGiftCertificate from '@/widgets/FormBuyGiftCertificate' import styles from './VouchersPage.module.scss' diff --git a/src/shared/config/routerConfig/routes.ts b/src/shared/config/routerConfig/routes.ts index d1e3438e..16563427 100644 --- a/src/shared/config/routerConfig/routes.ts +++ b/src/shared/config/routerConfig/routes.ts @@ -15,6 +15,7 @@ export enum Routes { PRIVACY = '/privacy', PRODUCTS = '/products/', PRODUCTS_ID = '/products/:id', + FEEDBACKS = '/feedbacks', REVIEWS = '/reviews', SEARCH = '/search/:query', TERMS = '/terms', diff --git a/src/shared/icons/MobileMenuIcon.svg b/src/shared/icons/MobileMenuIcon.svg new file mode 100644 index 00000000..16ce1edf --- /dev/null +++ b/src/shared/icons/MobileMenuIcon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/shared/libs/helpers/scrollPageToTop.ts b/src/shared/libs/helpers/scrollPageToTop.ts new file mode 100644 index 00000000..2decd7ff --- /dev/null +++ b/src/shared/libs/helpers/scrollPageToTop.ts @@ -0,0 +1,6 @@ +/** + * Функция выполняет скролл в верх страницы + */ +export const scrollPageToTop = () => { + window.scrollTo(0, 0) +} diff --git a/src/shared/mockData/catalogListData.ts b/src/shared/mockData/catalogListData.ts index d01f615f..2435250c 100644 --- a/src/shared/mockData/catalogListData.ts +++ b/src/shared/mockData/catalogListData.ts @@ -3,7 +3,7 @@ import { Routes } from '@/shared/config/routerConfig/routes' export const linkItems = [ { index: 0, label: 'Блог', to: Routes.BLOG }, { index: 1, label: 'Новости', to: Routes.NEWS }, - { index: 2, label: 'Отзывы о магазине', to: `${Routes.REVIEWS}/0` }, + { index: 2, label: 'Отзывы о магазине', to: `${Routes.FEEDBACKS}/0` }, { index: 3, label: 'Контакты', to: Routes.CONTACTS } ] diff --git a/src/shared/styles/utils/_mixins.scss b/src/shared/styles/utils/_mixins.scss index 9dcfe10f..5ec1224b 100644 --- a/src/shared/styles/utils/_mixins.scss +++ b/src/shared/styles/utils/_mixins.scss @@ -10,6 +10,9 @@ $breakpoints: ( 'middle': ( max-width: 769px ), + 'small-middle': ( + max-width: 576px + ), 'small': ( max-width: 390px ) diff --git a/src/components/Dropdown/Dropdown.module.scss b/src/shared/ui/Dropdown/Dropdown.module.scss similarity index 100% rename from src/components/Dropdown/Dropdown.module.scss rename to src/shared/ui/Dropdown/Dropdown.module.scss diff --git a/src/components/Dropdown/Dropdown.tsx b/src/shared/ui/Dropdown/Dropdown.tsx similarity index 95% rename from src/components/Dropdown/Dropdown.tsx rename to src/shared/ui/Dropdown/Dropdown.tsx index b55b2937..e6b1c1a7 100644 --- a/src/components/Dropdown/Dropdown.tsx +++ b/src/shared/ui/Dropdown/Dropdown.tsx @@ -1,6 +1,6 @@ import React, { ChangeEvent, useState } from 'react' -import type { TSortOptions } from '@/components/PageControls/PageControls' +import type { TSortOptions } from '@/widgets/PageControls/PageControls' import styles from './Dropdown.module.scss' diff --git a/src/components/Dropdown/selectors/selectors.tsx b/src/shared/ui/Dropdown/selectors/selectors.tsx similarity index 100% rename from src/components/Dropdown/selectors/selectors.tsx rename to src/shared/ui/Dropdown/selectors/selectors.tsx diff --git a/src/components/Dropdown/slice/filtersSlice.tsx b/src/shared/ui/Dropdown/slice/filtersSlice.tsx similarity index 90% rename from src/components/Dropdown/slice/filtersSlice.tsx rename to src/shared/ui/Dropdown/slice/filtersSlice.tsx index 688a2977..e7a7e1ad 100644 --- a/src/components/Dropdown/slice/filtersSlice.tsx +++ b/src/shared/ui/Dropdown/slice/filtersSlice.tsx @@ -1,7 +1,7 @@ import { createSlice } from '@reduxjs/toolkit' -import type { ICategoryFiltersSchema } from '@/components/Dropdown/types/types' import { SORT_NAMES, SORT_VALUES } from '@/shared/constants/constants' +import type { ICategoryFiltersSchema } from '@/shared/ui/Dropdown/types/types' const initialState: ICategoryFiltersSchema = { filterProducts: { name: SORT_NAMES.NAMES_A_YA, value: SORT_VALUES.NAMES_A_YA }, diff --git a/src/components/Dropdown/types/types.ts b/src/shared/ui/Dropdown/types/types.ts similarity index 100% rename from src/components/Dropdown/types/types.ts rename to src/shared/ui/Dropdown/types/types.ts diff --git a/src/components/WrapperForMainContent/WrapperForMainContent.tsx b/src/shared/ui/WrapperForMainContent/WrapperForMainContent.tsx similarity index 100% rename from src/components/WrapperForMainContent/WrapperForMainContent.tsx rename to src/shared/ui/WrapperForMainContent/WrapperForMainContent.tsx diff --git a/src/components/WrapperForMainContent/wrapper.module.scss b/src/shared/ui/WrapperForMainContent/wrapper.module.scss similarity index 100% rename from src/components/WrapperForMainContent/wrapper.module.scss rename to src/shared/ui/WrapperForMainContent/wrapper.module.scss diff --git a/src/widgets/AccountCart/ui/AccountCartCard/AccountCartCard.tsx b/src/widgets/AccountCart/ui/AccountCartCard/AccountCartCard.tsx index feb522d5..6490bbc1 100644 --- a/src/widgets/AccountCart/ui/AccountCartCard/AccountCartCard.tsx +++ b/src/widgets/AccountCart/ui/AccountCartCard/AccountCartCard.tsx @@ -1,7 +1,7 @@ import { FC, useState } from 'react' import { useWithFavorite } from '@/entities/Favorite/model/hooks/useWithFavorie' -import { WidgetButtonsFunctions } from '@/features/WidgetButtonsFunctions/WidgetButtonsFunctions' +import { WidgetButtonsFunctions } from '@/entities/WidgetButtonsFunctions/WidgetButtonsFunctions' import { Routes } from '@/shared/config/routerConfig/routes' import { ECardView } from '@/shared/model/types/common' import { IProduct } from '@/shared/model/types/ProductModel' diff --git a/src/widgets/BlogMain/index.tsx b/src/widgets/BlogMain/index.tsx new file mode 100644 index 00000000..d17d36f8 --- /dev/null +++ b/src/widgets/BlogMain/index.tsx @@ -0,0 +1,2 @@ +import BlogMain from './ui/BlogMain' +export default BlogMain diff --git a/src/widgets/BlogMain/ui/BlogMain.stories.tsx b/src/widgets/BlogMain/ui/BlogMain.stories.tsx new file mode 100644 index 00000000..2dbbf808 --- /dev/null +++ b/src/widgets/BlogMain/ui/BlogMain.stories.tsx @@ -0,0 +1,25 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import BlogMain from './BlogMain' + +const meta = { + title: 'widgets/BlogMain', + component: BlogMain, + parameters: { + layout: 'centered' + }, + tags: ['autodocs'] +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = () => { + return ( +
    + +
    + ) +} + +Default.args = {} diff --git a/src/widgets/BlogMain/ui/BlogMain.tsx b/src/widgets/BlogMain/ui/BlogMain.tsx new file mode 100644 index 00000000..31a75908 --- /dev/null +++ b/src/widgets/BlogMain/ui/BlogMain.tsx @@ -0,0 +1,63 @@ +import { FC, useEffect } from 'react' +import { useSelector } from 'react-redux' + +// import { Pagination } from '@/components/Pagination/Pagination' + +import BlogCard from '@/entities/BlogCard' +import BlogMainItem from '@/entities/BlogMainItem' +import { useAppDispatch } from '@/shared/libs/hooks/store' +import { useResize } from '@/shared/libs/hooks/useResize' + +import { getBlogPostsSelector } from '../../BlogBlock/model/selectors/selectors' +import { getBlogPosts } from '../../BlogBlock/model/services/getBlogPosts' +import { IBlogPostData } from '../../BlogBlock/model/types/types' + +import styles from './blog-main.module.scss' + +/** + * Компонент BlogMain это основной контент который отрисовывается на странице BlogPage + */ + +const BlogMain: FC = () => { + const dispatch = useAppDispatch() + const posts: IBlogPostData[] = useSelector(getBlogPostsSelector) + const { isScreenMd } = useResize() + + useEffect(() => { + dispatch(getBlogPosts()) + }, []) + + return ( +
    + {/* Это временный компонент */} + {isScreenMd && } + +
      + {posts.map(item => ( +
    • + +
    • + ))} +
    + + {/* Далее буду использовать пагинацию, как это сделано на странице ProductsPage + + */} +
    + ) +} + +export default BlogMain diff --git a/src/widgets/BlogMain/ui/blog-main.module.scss b/src/widgets/BlogMain/ui/blog-main.module.scss new file mode 100644 index 00000000..3761ee7b --- /dev/null +++ b/src/widgets/BlogMain/ui/blog-main.module.scss @@ -0,0 +1,24 @@ +@use '@/shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/mixins' as media; + +.blogMain { + display: flex; + flex-direction: column; + gap: 30px; + + &__list { + display: grid; + grid-template-columns: repeat(3, 1fr); + width: 100%; + column-gap: 20px; + row-gap: 30px; + + @include media.respond-to('middle') { + grid-template-columns: repeat(2, 1fr); + } + + @include media.respond-to('small-middle') { + grid-template-columns: 1fr; + } + } +} diff --git a/src/widgets/CategoryCardList/CategoryCardList.module.scss b/src/widgets/CategoryCardList/CategoryCardList.module.scss index 53f3cf73..9e406194 100644 --- a/src/widgets/CategoryCardList/CategoryCardList.module.scss +++ b/src/widgets/CategoryCardList/CategoryCardList.module.scss @@ -1,9 +1,9 @@ -.categoryCardList{ - margin-right: 24px; - display: grid; - justify-content: center; - row-gap: 19px; - column-gap: 19px; - grid-template-columns: repeat(auto-fit, 255px); - margin-bottom: 115px; -} \ No newline at end of file +.categoryCardList { + margin-top: 24px; + display: grid; + justify-content: space-between; + row-gap: 19px; + column-gap: 19px; + grid-template-columns: repeat(auto-fit, minmax(255px, 1fr)); + margin-bottom: 115px; +} diff --git a/src/widgets/CategoryList/CategoryList.module.scss b/src/widgets/CategoryList/CategoryList.module.scss index 5dd7bbec..c0337e1d 100644 --- a/src/widgets/CategoryList/CategoryList.module.scss +++ b/src/widgets/CategoryList/CategoryList.module.scss @@ -1,9 +1,8 @@ -@use '../../shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/mixins' as media; .category-list { padding: 30px; - max-width: 330px; - height: fit-content; background-color: var.$white; border-radius: 10px; width: inherit; diff --git a/src/widgets/CategoryList/CategoryList.tsx b/src/widgets/CategoryList/CategoryList.tsx index d6fa066f..eaa271ff 100644 --- a/src/widgets/CategoryList/CategoryList.tsx +++ b/src/widgets/CategoryList/CategoryList.tsx @@ -1,3 +1,4 @@ +import classNames from 'classnames' import { type FC, useEffect } from 'react' import { useSelector } from 'react-redux' import { useParams } from 'react-router-dom' @@ -19,7 +20,11 @@ import styles from './CategoryList.module.scss' * Список категорий для страницы товаров. * Фиксированная высота настраивается классом .category-list__items */ -export const CategoryList: FC = () => { + +type TCategoryList = { + className?: string +} +export const CategoryList: FC = ({ className }) => { const dispatch = useAppDispatch() const getMainCategories = useSelector(getCategorySelector) const categorySlug = useSelector(selectCategorySlug) @@ -34,7 +39,7 @@ export const CategoryList: FC = () => { }, [categorySlug, slug]) return ( -
    +
    Категории diff --git a/src/widgets/CategoryList/CategoryListMobilePopup/CategoryListMobilePopup.module.scss b/src/widgets/CategoryList/CategoryListMobilePopup/CategoryListMobilePopup.module.scss new file mode 100644 index 00000000..4d60d98e --- /dev/null +++ b/src/widgets/CategoryList/CategoryListMobilePopup/CategoryListMobilePopup.module.scss @@ -0,0 +1,56 @@ +@use '@/shared/styles/utils/mixins' as media; + +.category-list { + display: block; +} + +.customButton { + display: none; + background-color: white; + + svg { + width: 20px; + height: 20px; + padding-left: 10px; + } + + @include media.respond-to('large') { + display: flex; + width: 310px; + } +} + +.buttonClose{ + background-color: white; + width: 100%; +} + +.modalBlock { + display: flex; + flex-direction: column; + gap: 10px; + width: inherit; + height: inherit; + padding: 15%; + + @include media.respond-to('middle') { + padding: 7%; + } + + @include media.respond-to('small') { + padding: 3%; + } +} + +.modal { + width: inherit; +} + +.mobileVisible { + @include media.respond-to('large') { + display: block; + width: 100%; + max-height: 500px; + } +} + diff --git a/src/widgets/CategoryList/CategoryListMobilePopup/CategoryListMobilePopup.tsx b/src/widgets/CategoryList/CategoryListMobilePopup/CategoryListMobilePopup.tsx new file mode 100644 index 00000000..ff928e43 --- /dev/null +++ b/src/widgets/CategoryList/CategoryListMobilePopup/CategoryListMobilePopup.tsx @@ -0,0 +1,46 @@ +import { type FC, useState } from 'react' + +import MobileMenuIcon from '@/shared/icons/MobileMenuIcon.svg' +import { Button, ButtonSize, ButtonTheme } from '@/shared/ui/Button/Button' +import Modal from '@/shared/ui/Modal/Modal' +import { CategoryList } from '@/widgets/CategoryList/CategoryList' +import styles from '@/widgets/CategoryList/CategoryListMobilePopup/CategoryListMobilePopup.module.scss' + +export const CategoryListMobilePopup: FC = () => { + const [isModalOpen, setIsModalOpen] = useState(false) + const [isModalClosing, setIsModalClosing] = useState(false) + const changeModalState = () => { + setIsModalOpen(!isModalOpen) + } + return ( + <> + + {isModalOpen && ( + +
    + + +
    +
    + )} + + ) +} diff --git a/src/widgets/FeedbackList/FeedbackList.tsx b/src/widgets/FeedbackList/FeedbackList.tsx index a465281a..c86350a3 100644 --- a/src/widgets/FeedbackList/FeedbackList.tsx +++ b/src/widgets/FeedbackList/FeedbackList.tsx @@ -8,7 +8,7 @@ import styles from './FeedbackList.module.scss' import type { IFeedback } from './model/types/types' interface IFeedbackListProps { - targetId: number + targetId: number | undefined feedbacks: IFeedback[] isLoading: boolean nextPage: Nullable @@ -33,7 +33,7 @@ export const FeedbackList: FC = ({ const virtuosoRef = useRef(null) useEffect(() => { - if (virtuosoRef && virtuosoRef.current) { + if (virtuosoRef && virtuosoRef.current && targetId) { virtuosoRef.current.scrollToIndex({ index: targetId, behavior: 'smooth' }) } }, [targetId]) diff --git a/src/widgets/NewsBlock/NewsBlockSkeleton/NewsBlockSkeleton.module.scss b/src/widgets/NewsBlock/NewsBlockSkeleton/NewsBlockSkeleton.module.scss new file mode 100644 index 00000000..c811f537 --- /dev/null +++ b/src/widgets/NewsBlock/NewsBlockSkeleton/NewsBlockSkeleton.module.scss @@ -0,0 +1,19 @@ +.skeletonNewsCard { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + background-color: #f0f0f0; + border-radius: 8px; + overflow: hidden; + margin-bottom: 16px; + } + + .content { + padding: 16px; + } + + .content > div { + margin-bottom: 8px; + } + \ No newline at end of file diff --git a/src/widgets/NewsBlock/NewsBlockSkeleton/NewsBlockSkeleton.tsx b/src/widgets/NewsBlock/NewsBlockSkeleton/NewsBlockSkeleton.tsx new file mode 100644 index 00000000..afc1cee0 --- /dev/null +++ b/src/widgets/NewsBlock/NewsBlockSkeleton/NewsBlockSkeleton.tsx @@ -0,0 +1,19 @@ +import { FC } from 'react' +import Skeleton from 'react-loading-skeleton' +import 'react-loading-skeleton/dist/skeleton.css' + +import styles from './NewsBlockSkeleton.module.scss' + +const NewsBlockSkeleton: FC = () => { + return ( +
    + +
    + + +
    +
    + ) +} + +export default NewsBlockSkeleton diff --git a/src/widgets/NewsBlock/ui/NewsBlock.tsx b/src/widgets/NewsBlock/ui/NewsBlock.tsx index 6e1c9ce5..c6d654b8 100644 --- a/src/widgets/NewsBlock/ui/NewsBlock.tsx +++ b/src/widgets/NewsBlock/ui/NewsBlock.tsx @@ -11,6 +11,7 @@ import Scroll from '@/shared/ui/Scroll/Scroll' import useNewsArray from '../model/hooks/useNewsArray' import { getShopNews } from '../model/services/getShopNews' +// import NewsBlockSkeleton from '../NewsBlockSkeleton/NewsBlockSkeleton' import styles from './NewsBlock.module.scss' @@ -36,6 +37,8 @@ const NewsBlock: FC = () => { {isScreenMd ? (
      + {/* TODO Переделать скелетон правильно, на основе стейта редакса isLoading */} + {/* Array.from({ length: 4 }).map((_, index) => ) */} {desktopNewsArray.map(item => (
    • { return ( diff --git a/src/components/PageControls/PageControlsSkeletons/PageControlsSkeletons.tsx b/src/widgets/PageControls/PageControlsSkeletons/PageControlsSkeletons.tsx similarity index 91% rename from src/components/PageControls/PageControlsSkeletons/PageControlsSkeletons.tsx rename to src/widgets/PageControls/PageControlsSkeletons/PageControlsSkeletons.tsx index e15eacb4..7219a71e 100644 --- a/src/components/PageControls/PageControlsSkeletons/PageControlsSkeletons.tsx +++ b/src/widgets/PageControls/PageControlsSkeletons/PageControlsSkeletons.tsx @@ -7,6 +7,7 @@ import styles from './PageControlsSkeletons.module.scss' export const PageControlsSkeletons: FC = () => { return (
      +
      diff --git a/src/components/PageDescription/PageDescription.module.scss b/src/widgets/PageDescription/PageDescription.module.scss similarity index 89% rename from src/components/PageDescription/PageDescription.module.scss rename to src/widgets/PageDescription/PageDescription.module.scss index cdf37807..bd857d33 100644 --- a/src/components/PageDescription/PageDescription.module.scss +++ b/src/widgets/PageDescription/PageDescription.module.scss @@ -1,4 +1,4 @@ -@use '../../shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/variables' as var; .content__description { display: flex; diff --git a/src/components/PageDescription/PageDescription.tsx b/src/widgets/PageDescription/PageDescription.tsx similarity index 100% rename from src/components/PageDescription/PageDescription.tsx rename to src/widgets/PageDescription/PageDescription.tsx diff --git a/src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.module.scss b/src/widgets/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.module.scss similarity index 79% rename from src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.module.scss rename to src/widgets/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.module.scss index 61a7cd45..ee22f575 100644 --- a/src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.module.scss +++ b/src/widgets/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.module.scss @@ -1,4 +1,4 @@ -@use '../../../shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/variables' as var; .sk-content { width: 330px; diff --git a/src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.stories.tsx b/src/widgets/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.stories.tsx similarity index 78% rename from src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.stories.tsx rename to src/widgets/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.stories.tsx index ea2a2d68..6dcf858c 100644 --- a/src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.stories.tsx +++ b/src/widgets/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.stories.tsx @@ -1,7 +1,7 @@ import { Meta, StoryObj } from '@storybook/react' import { type FC } from 'react' -import { PageDescriptionSkeleton } from '@/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton' +import { PageDescriptionSkeleton } from '@/widgets/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton' const StorybookWrapper: FC = () => { return ( diff --git a/src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.tsx b/src/widgets/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.tsx similarity index 77% rename from src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.tsx rename to src/widgets/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.tsx index 9de55a5e..01b605cf 100644 --- a/src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.tsx +++ b/src/widgets/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.tsx @@ -1,7 +1,7 @@ import { type FC } from 'react' import Skeleton from 'react-loading-skeleton' -import styles from '@/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.module.scss' +import styles from '@/widgets/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.module.scss' export const PageDescriptionSkeleton: FC = () => { return ( diff --git a/src/components/Pagination/Pagination.module.scss b/src/widgets/Pagination/Pagination.module.scss similarity index 92% rename from src/components/Pagination/Pagination.module.scss rename to src/widgets/Pagination/Pagination.module.scss index a6698272..9de33192 100644 --- a/src/components/Pagination/Pagination.module.scss +++ b/src/widgets/Pagination/Pagination.module.scss @@ -1,4 +1,4 @@ -@use '../../shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/variables' as var; .pagination { display: flex; diff --git a/src/components/Pagination/Pagination.tsx b/src/widgets/Pagination/Pagination.tsx similarity index 100% rename from src/components/Pagination/Pagination.tsx rename to src/widgets/Pagination/Pagination.tsx diff --git a/src/components/Pagination/selectors/selectors.tsx b/src/widgets/Pagination/selectors/selectors.tsx similarity index 100% rename from src/components/Pagination/selectors/selectors.tsx rename to src/widgets/Pagination/selectors/selectors.tsx diff --git a/src/components/Pagination/slice/paginationSlice.tsx b/src/widgets/Pagination/slice/paginationSlice.tsx similarity index 84% rename from src/components/Pagination/slice/paginationSlice.tsx rename to src/widgets/Pagination/slice/paginationSlice.tsx index 7461998e..ab999bb4 100644 --- a/src/components/Pagination/slice/paginationSlice.tsx +++ b/src/widgets/Pagination/slice/paginationSlice.tsx @@ -1,6 +1,6 @@ import { createSlice } from '@reduxjs/toolkit' -import type { TNumberOfPageSchema } from '@/components/Pagination/types/types' +import type { TNumberOfPageSchema } from '@/widgets/Pagination/types/types' const initialState: TNumberOfPageSchema = { numberOfPage: 1 diff --git a/src/components/Pagination/types/types.ts b/src/widgets/Pagination/types/types.ts similarity index 100% rename from src/components/Pagination/types/types.ts rename to src/widgets/Pagination/types/types.ts diff --git a/src/widgets/Product/Product.module.scss b/src/widgets/Product/Product.module.scss index 6b3e9a50..5df770d2 100644 --- a/src/widgets/Product/Product.module.scss +++ b/src/widgets/Product/Product.module.scss @@ -115,3 +115,21 @@ fill: var.$white; } } + +.customButton { + max-width: 200px; + min-height: 50px; + padding: 5px; + display: flex; + align-items: center; + justify-content: center; + gap: 5px; + cursor: pointer; + transition: background-color 0.2s ease-in-out; + + svg { + width: 25px; + min-width: 25px; + height: 25px; + } +} diff --git a/src/widgets/Product/Product.tsx b/src/widgets/Product/Product.tsx index 1790fb9a..79321ebc 100644 --- a/src/widgets/Product/Product.tsx +++ b/src/widgets/Product/Product.tsx @@ -1,11 +1,12 @@ import { type FC, useState } from 'react' import IconCart from '@/assets/icons/IconCart.svg' +import WB from '@/assets/icons/WB.svg' import { useProductInCart } from '@/entities/CartEntity/model/hooks/cartHooks' import { useWithFavorite } from '@/entities/Favorite/model/hooks/useWithFavorie' +import { ProductAvailability } from '@/entities/ProductAvailability/ProductAvailability' +import { ProductImgCarousel } from '@/entities/ProductImgCarousel/ProductImgCarousel' import { CardPreviewHeader } from '@/features/CardPreviewHeader/CardPreviewHeader' -import { ProductAvailability } from '@/features/ProductAvailability/ProductAvailability' -import { ProductImgCarousel } from '@/features/ProductImgCarousel/ProductImgCarousel' import type { IProduct } from '@/shared/model/types/ProductModel' import { Button, ButtonSize, ButtonTheme } from '@/shared/ui/Button/Button' import Paragraph from '@/shared/ui/Paragraph/Paragraph' @@ -35,6 +36,10 @@ export const Product: FC = ({ product }) => { //TODO реализовать форму быстрого заказа } + const buyWBHandle = () => { + window.open(product.wb_urls, '_blank') + } + return (
      @@ -68,6 +73,16 @@ export const Product: FC = ({ product }) => { {isInCart ? 'Перейти в корзину' : 'Купить'} + {product.wb_urls && ( + + )}
      diff --git a/src/widgets/SideBarBlog/index.tsx b/src/widgets/SideBarBlog/index.tsx new file mode 100644 index 00000000..8ac452b0 --- /dev/null +++ b/src/widgets/SideBarBlog/index.tsx @@ -0,0 +1,2 @@ +import SideBarBlog from './ui/SideBarBlog' +export default SideBarBlog diff --git a/src/widgets/SideBarBlog/ui/SideBarBlog.module.scss b/src/widgets/SideBarBlog/ui/SideBarBlog.module.scss new file mode 100644 index 00000000..6c5add60 --- /dev/null +++ b/src/widgets/SideBarBlog/ui/SideBarBlog.module.scss @@ -0,0 +1,20 @@ +@use '@/shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/mixins' as media; + +.sideBarBlog { + display: flex; + flex-direction: column; + width: 100%; + max-width: 340px; + height: fit-content; + border-radius: 10px; + background: var.$white; + padding: 30px; + + @include media.respond-to('large') { + max-width: 100%; + border-radius: none; + background: var.$body-bg; + padding: 0; + } +} diff --git a/src/widgets/SideBarBlog/ui/SideBarBlog.stories.tsx b/src/widgets/SideBarBlog/ui/SideBarBlog.stories.tsx new file mode 100644 index 00000000..66c74675 --- /dev/null +++ b/src/widgets/SideBarBlog/ui/SideBarBlog.stories.tsx @@ -0,0 +1,25 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import SideBarBlog from './SideBarBlog' + +const meta = { + title: 'widgets/SideBarBlog', + component: SideBarBlog, + parameters: { + layout: 'centered' + }, + tags: ['autodocs'] +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = () => { + return ( +
      + +
      + ) +} + +Default.args = {} diff --git a/src/widgets/SideBarBlog/ui/SideBarBlog.tsx b/src/widgets/SideBarBlog/ui/SideBarBlog.tsx new file mode 100644 index 00000000..b497b284 --- /dev/null +++ b/src/widgets/SideBarBlog/ui/SideBarBlog.tsx @@ -0,0 +1,41 @@ +import { FC, useState } from 'react' + +import BlogCategories from '@/entities/BlogCategories' +import BlogTags from '@/entities/BlogTags' +import { blogPageData } from '@/mockData/blogPageData' +import { useResize } from '@/shared/libs/hooks/useResize' + +import styles from './SideBarBlog.module.scss' + +/** + * Компонент SideBarBlog - это боковая панель навигации, используется на странице BlogPage + */ + +const SideBarBlog: FC = () => { + const { isScreenLg } = useResize() + + const [items, setItems] = useState(blogPageData) + + const filterCategories = (curcat?: string) => { + const newItems = items.filter(newVal => { + return newVal.category === curcat + }) + setItems(newItems) + } + + const filterTags = (curcat: string) => { + const newItems = items.filter(newVal => { + return newVal.tags.includes(curcat) + }) + setItems(newItems) + } + + return ( + + ) +} + +export default SideBarBlog diff --git a/src/widgets/StoriesBlock/StoriesBlockSkeleton/StoriesBlockSkeleton.module.scss b/src/widgets/StoriesBlock/StoriesBlockSkeleton/StoriesBlockSkeleton.module.scss new file mode 100644 index 00000000..1c7acfd1 --- /dev/null +++ b/src/widgets/StoriesBlock/StoriesBlockSkeleton/StoriesBlockSkeleton.module.scss @@ -0,0 +1,13 @@ +.skeletonNewsCard { + display: flex; + flex-direction: column; + justify-content: space-between; + width: 160px; + height: 100%; + background-color: #f0f0f0; + border-radius: 8px; + overflow: hidden; + margin:0; + } + + \ No newline at end of file diff --git a/src/widgets/StoriesBlock/StoriesBlockSkeleton/StoriesBlockSkeleton.tsx b/src/widgets/StoriesBlock/StoriesBlockSkeleton/StoriesBlockSkeleton.tsx new file mode 100644 index 00000000..609b9325 --- /dev/null +++ b/src/widgets/StoriesBlock/StoriesBlockSkeleton/StoriesBlockSkeleton.tsx @@ -0,0 +1,15 @@ +import { FC } from 'react' +import Skeleton from 'react-loading-skeleton' +import 'react-loading-skeleton/dist/skeleton.css' + +import styles from './StoriesBlockSkeleton.module.scss' + +const StoriesBlockSkeleton: FC = () => { + return ( +
      + +
      + ) +} + +export default StoriesBlockSkeleton diff --git a/src/widgets/StoriesBlock/ui/StoriesBlock.module.scss b/src/widgets/StoriesBlock/ui/StoriesBlock.module.scss index 57b10132..c2b976be 100644 --- a/src/widgets/StoriesBlock/ui/StoriesBlock.module.scss +++ b/src/widgets/StoriesBlock/ui/StoriesBlock.module.scss @@ -10,4 +10,14 @@ .storiesScroll { padding-top: 20px; + overflow-y: auto; + display: flex; + gap: 16px; } + +.storiesBlock li { + list-style: none; + margin: 0; + padding: 0; + width: 160px; +} \ No newline at end of file diff --git a/src/widgets/StoriesBlock/ui/StoriesBlock.tsx b/src/widgets/StoriesBlock/ui/StoriesBlock.tsx index 9849cf34..18722071 100644 --- a/src/widgets/StoriesBlock/ui/StoriesBlock.tsx +++ b/src/widgets/StoriesBlock/ui/StoriesBlock.tsx @@ -10,6 +10,7 @@ import Scroll from '@/shared/ui/Scroll/Scroll' import { getStoriesSelector } from '../model/selectors/selectors' import { getStories } from '../model/services/getStories' import { IStoriesData } from '../model/types/types' +import StoriesBlockSkeleton from '../StoriesBlockSkeleton/StoriesBlockSkeleton' import styles from './StoriesBlock.module.scss' @@ -20,25 +21,30 @@ import styles from './StoriesBlock.module.scss' const StoriesBlock: FC = () => { const dispatch = useAppDispatch() const stories: IStoriesData[] = useSelector(getStoriesSelector) + const isLoading = stories.length === 0 useEffect(() => { dispatch(getStories()) }, []) return ( - stories.length != 0 && ( -
      - - - - {stories.map(item => ( -
    • - item.image)} /> -
    • - ))} -
      -
      - ) +
      + + + + {isLoading + ? Array.from({ length: 8 }).map((_, index) => ( +
    • + +
    • + )) + : stories.map(item => ( +
    • + picture.image)} /> +
    • + ))} +
      +
      ) } diff --git a/src/widgets/ViewedProducts/ui/ViewedProducts.tsx b/src/widgets/ViewedProducts/ui/ViewedProducts.tsx index 7f663cc7..422551af 100644 --- a/src/widgets/ViewedProducts/ui/ViewedProducts.tsx +++ b/src/widgets/ViewedProducts/ui/ViewedProducts.tsx @@ -1,10 +1,10 @@ import { FC } from 'react' +import { ProductItem } from '@/features/ProductItem/ProductItem' import { VIEWED_PRODUCTS_COUNT_ON_MAIN } from '@/shared/constants/constants' import { ECardView } from '@/shared/model/types/common' import Heading from '@/shared/ui/Heading/Heading' import Scroll from '@/shared/ui/Scroll/Scroll' -import { ProductItem } from '@/widgets/ProductItem/ProductItem' import { getViewedProductsFromStorage } from '../model/functions/functions' @@ -24,9 +24,6 @@ interface IViewedProductsProps { const ViewedProducts: FC = ({ title, hasLabel }) => { const viewedProducts = getViewedProductsFromStorage() - { - /*TODO по FSD нельзя использовать widget ProductItem в widget, нужно перенести ProductItem в features или entities*/ - } const productList = viewedProducts.map((item, index) => { if (hasLabel && index > VIEWED_PRODUCTS_COUNT_ON_MAIN) return @@ -45,6 +42,7 @@ const ViewedProducts: FC = ({ title, hasLabel }) => { label_hit={item.label_hit} label_popular={item.label_popular} quantity={item.quantity} + wb_urls={item.wb_urls} /> ) })