Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Enhancement 163 header core api #227

Merged
merged 13 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/app/providers/StoreProvider/config/StateSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import { ApiInstance } from '@/shared/api/api'
import { ShopNewsSchema } from '@/widgets/NewsBlock/model/types/types'
import { StoreReviewsSchema } from '@/widgets/ReviewsBlock/model/types/types'
import { CoreBaseFooterSchema } from '@/widgets/Footer/model/types/types'
import { CoreBaseHeaderSchema } from '@/widgets/Header/model/types/types'

export interface StateSchema {
login: LoginSchema
storeReviews: StoreReviewsSchema
category: CategorySchema
coreBaseFooter: CoreBaseFooterSchema
coreBaseHeader: CoreBaseHeaderSchema
brand: BrandSchema
searchResult: SearchResultSchema
shopNews: ShopNewsSchema
Expand Down
6 changes: 5 additions & 1 deletion src/app/providers/StoreProvider/config/store.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import { configureStore, ReducersMapObject } from '@reduxjs/toolkit'

import { loginReducer } from '@/features/login/model/slice/loginSlice'
import { StateSchema, ThunkExtraArg } from './StateSchema'
import { $api } from '@/shared/api/api'
import categorySlice from '@/entities/Category/slice/categorySlice'
import brandSlice from '@/widgets/BrandBlock/slice/brandSlice'
import searchProductSlice from '@/features/SearchProduct/slice/searchProductSlice'
import { storeReviewsReducer } from '@/widgets/ReviewsBlock/model/slice/reviewsSlice'
import footerSlice from '@/widgets/Footer/model/slice/footerSlice'
import { shopNewsReducer } from '@/widgets/NewsBlock/model/slice/shopNewsSlice'
import headerSlice from '@/widgets/Header/model/slice/headerSlice'

import { StateSchema, ThunkExtraArg } from './StateSchema'

export type RootState = StateSchema

const rootReducer: ReducersMapObject<RootState> = {
login: loginReducer,
category: categorySlice,
coreBaseHeader: headerSlice,
coreBaseFooter: footerSlice,
brand: brandSlice,
searchResult: searchProductSlice,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Meta, Story } from '@storybook/react'
import SearchResult from './SearchResult'

import { searchResponseData } from '@/mockData/searchData'

import SearchResult from './SearchResult'

export default {
title: 'Widgets/SearchResult',
component: SearchResult
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { forwardRef } from 'react'

import SearchItem from '@/entities/SearchItem/SearchItem'
import { TCategory } from '@/models/CategoryModel'
import { Routes } from '@/shared/config/routerConfig/routes'
import { SEARCH_CATEGORY, SEARCH_PRODUCT } from '@/shared/constants/constants'
import type { TProduct } from '@/shared/model/types/common'
import { TCategory } from '@/models/CategoryModel'
import SearchIcon from '@/assets/images/search/search-icon.svg'
import Link from '@/shared/ui/Link/Link'
import { Routes } from '@/shared/config/routerConfig/routes'

import SearchIcon from './icons/search-icon.svg'
import styles from './SearchResult.module.scss'

type TProps = {
Expand Down
10 changes: 6 additions & 4 deletions src/features/SearchProduct/ui/SearchProduct.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { useRef, useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'

import SearchResult from '@/entities/SearchResult/SearchResult'
import { searchResponseData } from '@/mockData/searchData'
import { Routes } from '@/shared/config/routerConfig/routes'
import { TResultData } from '@/shared/model/types/common'
import SearchResult from '@/widgets/SearchResult/SearchResult'
import { Input, InputSize, InputTheme } from '@/shared/ui/Input/Input'
import { Button, ButtonDesign, ButtonSize, ButtonTheme } from '@/shared/ui/Button/Button'
import { Input, InputSize, InputTheme } from '@/shared/ui/Input/Input'

import styles from './SearchProduct.module.scss'
import { Routes } from '@/shared/config/routerConfig/routes'
import { useNavigate } from 'react-router-dom'

// @TODO: Перевести форму на Formik + Yup
// https://github.com/Studio-Yandex-Practicum/maxboom_frontend/issues/92
Expand Down
8 changes: 5 additions & 3 deletions src/pages/RootPage/RootPage.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { Outlet } from 'react-router'
import Header from '@/components/header/header'

import Contact from '@/features/Contacts/Contacts'
import { messengerArray } from '@/shared/model/types/messengerArray'
import Footer from '@/widgets/Footer/Footer'
import Header from '@/widgets/Header/Header'

import styles from './root.module.scss'
import Contact from '../../features/Contacts/Contacts'
import { messengerArray } from '@/shared/model/types/messengerArray'

const RootPage = () => {
return (
Expand Down
File renamed without changes
4 changes: 2 additions & 2 deletions src/widgets/Footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import Paragraph from '@/shared/ui/Paragraph/Paragraph'

import styles from './footer.module.scss'
import { getCoreBaseFooterSelector } from './model/selectors/selectors'
import { getCoreBase } from './model/services/getCoreBase'
import { getCoreBaseFooter } from './model/services/getCoreBaseFooter'

function Footer() {
const dispatch = useDispatch<AppDispatch>()
Expand All @@ -26,7 +26,7 @@ function Footer() {
}

useEffect(() => {
dispatch(getCoreBase())
dispatch(getCoreBaseFooter())
}, [])

const onSubmitHandler = () => {}
Expand Down
File renamed without changes
File renamed without changes
File renamed without changes
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { ApiError, ApiErrorTypes, ApiRoutes } from '@/shared/api/types'

import { CoreBaseFooterData } from '../types/types'

export const getCoreBase = createAsyncThunk<CoreBaseFooterData, void, ThunkConfig<ApiError>>(
export const getCoreBaseFooter = createAsyncThunk<CoreBaseFooterData, void, ThunkConfig<ApiError>>(
//void1- выходные данные, void2- входные данные , thunkConfig- тип store
'core/base', // action type, первый аргумент
'core/base_footer', // action type, первый аргумент
async (_, thunkAPI) => {
// второй аргумент- асинхронная функция , кот вызовет dispatch в компоненте
const { rejectWithValue, extra } = thunkAPI
Expand Down
8 changes: 4 additions & 4 deletions src/widgets/Footer/model/slice/footerSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createSlice } from '@reduxjs/toolkit'

import { rejectedPayloadHandle } from '@/shared/api/rejectedPayloadHandle'

import { getCoreBase } from '../services/getCoreBase'
import { getCoreBaseFooter } from '../services/getCoreBaseFooter'
import { CoreBaseFooterSchema } from '../types/types'

const initialState: CoreBaseFooterSchema = {
Expand Down Expand Up @@ -31,15 +31,15 @@ const footerSlice = createSlice({
reducers: {},
extraReducers: builder => {
builder
.addCase(getCoreBase.pending, state => {
.addCase(getCoreBaseFooter.pending, state => {
state.isLoading = true
state.error = undefined
})
.addCase(getCoreBase.fulfilled, (state, { payload }) => {
.addCase(getCoreBaseFooter.fulfilled, (state, { payload }) => {
state.isLoading = false
state.footer = payload
})
.addCase(getCoreBase.rejected, (state, { payload }) => {
.addCase(getCoreBaseFooter.rejected, (state, { payload }) => {
state.isLoading = false
state.error = rejectedPayloadHandle(payload)
})
Expand Down
43 changes: 26 additions & 17 deletions src/components/header/header.tsx → src/widgets/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,35 @@
import { coreBaseData } from '@/mockData/coreBaseData'
import { useEffect, useMemo } from 'react'
import classNames from 'classnames'
import Logo from '../../shared/ui/logo/Logo'
import ArrowIcon from '@/assets/icons/arrow.svg'
import LightningIcon from '@/assets/images/header/lightning.svg'
import ContextMenuElement from '../ContextMenuElement/ContextMenuElement'
import HeaderAccount from '../HeaderAccount/HeaderAccount'
import { PHONE_NUMBER } from '@/shared/constants/constants'
import { headerAccountData } from '@/mockData/headerAccountData'
import CatalogLink from '../CatalogLink/CatalogLink'
import { Routes } from '@/shared/config/routerConfig/routes'
import Link from '@/shared/ui/Link/Link'
import IconCategories from '@/assets/icons/IconCategories.svg'
import SearchProduct from '@/features/SearchProduct'
import { linkItems } from '@/mockData/catalogListData'
import styles from './header.module.scss'
import { useEffect, useMemo } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { fetchCategories } from '@/entities/Category/slice/categorySlice'

import { AppDispatch } from '@/app/providers/StoreProvider/config/store'
import CatalogLink from '@/components/CatalogLink/CatalogLink'
import ContextMenuElement from '@/components/ContextMenuElement/ContextMenuElement'
import HeaderAccount from '@/components/HeaderAccount/HeaderAccount'
import { selectCategories, selectDisplayedCategories } from '@/entities/Category/selectors/categorySelectors'
import { fetchCategories } from '@/entities/Category/slice/categorySlice'
import SearchProduct from '@/features/SearchProduct'
import { linkItems } from '@/mockData/catalogListData'
// import { coreBaseData } from '@/mockData/coreBaseData'
import { headerAccountData } from '@/mockData/headerAccountData'
Copy link
Collaborator

Choose a reason for hiding this comment

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

нужен комментарий?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

раньше данные получались из мок, теперь с сервера, можно и удалить в целом

import { Routes } from '@/shared/config/routerConfig/routes'
import { PHONE_NUMBER } from '@/shared/constants/constants'
import ArrowIcon from '@/shared/icons/arrow.svg'
import IconCategories from '@/shared/icons/IconCategories.svg'
import Link from '@/shared/ui/Link/Link'
import Logo from '@/shared/ui/logo/Logo'
import CatalogNodeItem from '@/widgets/CatalogNodeItem/CatalogNodeItem'
import NavigationLink from '@/widgets/NavigationLink/NavigationLink'

import styles from './header.module.scss'
import LightningIcon from './icons/lightning.svg'
import { getCoreBaseHeaderSelector } from './model/selectors/selectors'
import { getCoreBaseHeader } from './model/services/getCoreBaseHeader'

function Header() {
const dispatch = useDispatch<AppDispatch>()
const categories = useSelector(selectCategories)
const coreBaseData = useSelector(getCoreBaseHeaderSelector)
const displayedCategories = useSelector(selectDisplayedCategories)

const aboutUsNode = useMemo(
Expand Down Expand Up @@ -108,6 +113,10 @@ function Header() {
[categories]
)

useEffect(() => {
dispatch(getCoreBaseHeader())
}, [])

useEffect(() => {
dispatch(fetchCategories())
}, [dispatch])
Expand Down
3 changes: 3 additions & 0 deletions src/widgets/Header/model/selectors/selectors.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { StateSchema } from '@/app/providers/StoreProvider'

export const getCoreBaseHeaderSelector = (state: StateSchema) => state.coreBaseHeader
29 changes: 29 additions & 0 deletions src/widgets/Header/model/services/getCoreBaseHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
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 { CoreBaseHeaderData } from '../types/types'

/**
* ассинхронный запрос Api через thunk Redux toolkit
* <CoreBaseHeaderData> - формат ожидаемого ответа
* <ThunkConfig> - формат запроса (описан в config StoreProvider)
* <ApiError> - формат ошибки API запроса (описан в типах API)
* первый аргумент - thunkConfig ID action type (отображается в dev tools)
* второй аргумент - асинхронная функция, которая вызовет dispatch в компоненте
*/

export const getCoreBaseHeader = createAsyncThunk<CoreBaseHeaderData, void, ThunkConfig<ApiError>>(
'core/base_header',
async (_, thunkAPI) => {
const { rejectWithValue, extra } = thunkAPI
try {
const response = await extra.api.get(`api/${ApiRoutes.CORE_BASE}`)
return response.data.header as CoreBaseHeaderData
} catch (error) {
return rejectWithValue(apiErrorIdentify(error, ApiErrorTypes.DATA_EMPTY_ERROR))
}
}
)
45 changes: 45 additions & 0 deletions src/widgets/Header/model/slice/headerSlice.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { createSlice } from '@reduxjs/toolkit'

import { rejectedPayloadHandle } from '@/shared/api/rejectedPayloadHandle'

import { getCoreBaseHeader } from '../services/getCoreBaseHeader'
import { CoreBaseHeaderSchema } from '../types/types'

const initialState: CoreBaseHeaderSchema = {
isLoading: false,
header: {
main_logo: {
image: '',
url: '',
title: ''
},
support: {
callback: '',
phone_number: ''
}
},
error: undefined
}

const footerSlice = createSlice({
name: 'header',
initialState,
reducers: {},
extraReducers: builder => {
builder
.addCase(getCoreBaseHeader.pending, state => {
state.isLoading = true
state.error = undefined
})
.addCase(getCoreBaseHeader.fulfilled, (state, { payload }) => {
state.isLoading = false
state.header = payload
})
.addCase(getCoreBaseHeader.rejected, (state, { payload }) => {
state.isLoading = false
state.error = rejectedPayloadHandle(payload)
})
}
})

export default footerSlice.reducer
21 changes: 21 additions & 0 deletions src/widgets/Header/model/types/types.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
interface Logo {
image: string
url: string
title: string
}

interface Support {
callback: string
phone_number: string
}

export interface CoreBaseHeaderData {
main_logo: Logo
support: Support
}

export interface CoreBaseHeaderSchema {
isLoading: boolean
header: CoreBaseHeaderData
error?: string | string[]
}
Loading