Skip to content

Commit

Permalink
#142-api-inserted-to-NewsBlock
Browse files Browse the repository at this point in the history
  • Loading branch information
JuliaAvramenko committed Jan 31, 2024
1 parent 44c0dce commit dbf6710
Show file tree
Hide file tree
Showing 12 changed files with 153 additions and 30 deletions.
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 @@ -2,13 +2,15 @@ import { CategorySchema } from '@/entities/Category/types/types'
import { SearchResultSchema } from '@/features/SearchProduct/types/types'
import { LoginSchema } from '@/features/login/model/types/types'
import { ApiInstance } from '@/shared/api/api'
import { ShopNewsSchema } from '@/widgets/NewsBlock/model/types/types'
import { StoreReviewsSchema } from '@/widgets/ReviewsBlock/model/types/types'

export interface StateSchema {
login: LoginSchema
storeReviews: StoreReviewsSchema
category: CategorySchema
searchResult: SearchResultSchema
shopNews: ShopNewsSchema
}

export interface ThunkExtraArg {
Expand Down
4 changes: 3 additions & 1 deletion src/app/providers/StoreProvider/config/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ import { $api } from '@/shared/api/api'
import categorySlice from '@/entities/Category/slice/categorySlice'
import searchProductSlice from '@/features/SearchProduct/slice/searchProductSlice'
import { storeReviewsReducer } from '@/widgets/ReviewsBlock/model/slice/reviewsSlice'
import { shopNewsReducer } from '@/widgets/NewsBlock/model/slice/shopNewsSlice'

export type RootState = StateSchema

const rootReducer: ReducersMapObject<RootState> = {
login: loginReducer,
category: categorySlice,
searchResult: searchProductSlice,
storeReviews: storeReviewsReducer
storeReviews: storeReviewsReducer,
shopNews: shopNewsReducer
}

export function createReduxStore(initialState: RootState) {
Expand Down
18 changes: 18 additions & 0 deletions src/assets/icons/image-not-found-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 9 additions & 6 deletions src/entities/NewsCard/NewsCard.module.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@use '@/app/styles/index' as var;

.card {
max-width: 340px;
min-width: 340px;
position: relative;
transition: transform 0.3s ease-in-out;
Expand All @@ -14,12 +15,6 @@
transition: transform 0.3s ease-in-out;
}

img {
border-radius: 6px;
transition: transform 0.3s ease-in-out;
scroll-snap-align: start;
}

.heading
{
font-size: #{'min(max(14px, 1.2vw), 16px)'};
Expand All @@ -46,4 +41,12 @@
line-height: 120%;
font-weight: 500;
}

.img {
height: 180px;
width: 100%;
border-radius: 6px;
transition: transform 0.3s ease-in-out;
scroll-snap-align: start;
}
}
13 changes: 4 additions & 9 deletions src/entities/NewsCard/NewsCard.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { Meta, StoryObj } from '@storybook/react'
import NewsCard from './NewsCard'
import Img1 from '@/assets/images/news/img-news-01.png'

const meta = {
title: 'entities/NewsCard',
Expand All @@ -16,13 +15,9 @@ type Story = StoryObj<typeof meta>

export const Default: Story = {
args: {
card: {
id: 1,
src: Img1,
alt: 'Покупай и не жди. До -50% на весь электротранспорт!',
title: 'Покупай и не жди. До -50% на весь электротранспорт!',
date: '15 Мая, 2022',
promo: true
}
id: 1,
image: 'http://gealit.ru/media/news/18.png',
title: 'Покупай и не жди. До -50% на весь электротранспорт!',
date: '2022-05-15'
}
}
32 changes: 23 additions & 9 deletions src/entities/NewsCard/NewsCard.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,42 @@
import { FC } from 'react'
import { TCard } from '@/models/CardModel'
import { TEXT_PROMO } from '@/shared/constants/constants'
import { FC, useMemo } from 'react'
import styles from './NewsCard.module.scss'
import Link from '@/shared/ui/Link/Link'
import Heading, { HeadingType } from '@/shared/ui/Heading/Heading'
import NoImage from '@/assets/icons/image-not-found-icon.svg'

export type Props = {
card: TCard
id: number
image: string
date: string
title: string
}

/**
* Карточка из блока группы новостей
* @param {TCard} card - параметры карточки из группы новостей
*/

const NewsCard: FC<Props> = ({ card }) => {
const NewsCard: FC<Props> = ({ image, date, title }) => {
const newDate = useMemo(() => {
const _parsedDate = new Date(date)
const year = _parsedDate.getFullYear()
const formatter = new Intl.DateTimeFormat('ru', { month: 'long', day: 'numeric' }).format(_parsedDate)

return `${formatter}, ${year}`
}, [date])

return (
<Link to={''} className={styles.card}>
<img src={card.src} alt={card.alt} draggable="false" />
{image ? (
<img src={image} alt={'новость'} draggable="false" className={styles.img} />
) : (
<NoImage className={styles.img} />
)}
<Heading type={HeadingType.NORMAL} className={styles.heading}>
{card.title}
{title}
</Heading>
<span>{card.date}</span>
{card.promo ? <span className={styles.promo}>{TEXT_PROMO}</span> : null}
<span>{newDate}</span>
{/* {promo ? <span className={styles.promo}>{TEXT_PROMO}</span> : null} */}
</Link>
)
}
Expand Down
3 changes: 2 additions & 1 deletion src/shared/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ export enum ApiRoutes {
LOGOUT = 'token/logout',
SEARCH = 'search',
STORE_REVIEWS = 'store-reviews',
CATEGORIES = 'catalogue/category'
CATEGORIES = 'catalogue/category',
SHOP_NEWS = 'shopnews'
}

export enum ApiErrorTypes {
Expand Down
5 changes: 5 additions & 0 deletions src/widgets/NewsBlock/model/selectors/selectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { StateSchema } from '@/app/providers/StoreProvider'

export const getShopNewsSelector = (state: StateSchema) => {
return state.shopNews.news
}
22 changes: 22 additions & 0 deletions src/widgets/NewsBlock/model/services/getShopNews.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { createAsyncThunk } from '@reduxjs/toolkit'
import { ThunkConfig } from '@/app/providers/StoreProvider/config/StateSchema'
import { ApiError, ApiErrorTypes, ApiRoutes } from '@/shared/api/types'
import { apiErrorIdentify } from '@/shared/api/apiErrorIdentify'
import { ShopNewsData } from '../types/types'

// export const getStoreReviews = createAsyncThunk<StoreReviewData[], void, ThunkConfig<ApiError>>(
export const getShopNews = createAsyncThunk<ShopNewsData[], void, ThunkConfig<ApiError>>(
//void1- выходные данные, void2- входные данные , thunkConfig- тип store
'shop-news', // action type, первый аргумент
async (_, thunkAPI) => {
// второй аргумент- асинхронная функция , кот вызовет dispatch в компоненте
const { rejectWithValue, extra } = thunkAPI
try {
const { data } = await extra.api.get(ApiRoutes.SHOP_NEWS)

return data.results
} catch (error) {
return rejectWithValue(apiErrorIdentify(error, ApiErrorTypes.DATA_EMPTY_ERROR))
}
}
)
29 changes: 29 additions & 0 deletions src/widgets/NewsBlock/model/slice/shopNewsSlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { createSlice } from '@reduxjs/toolkit'
import { getShopNews } from '../services/getShopNews'
import { ShopNewsSchema } from '../types/types'

const initialState: ShopNewsSchema = {
isLoading: false,
news: []
}

export const shopNewsSlice = createSlice({
name: 'shopNews',
initialState,
reducers: {},
extraReducers: builder => {
builder
.addCase(getShopNews.pending, state => {
state.isLoading = true
})
.addCase(getShopNews.fulfilled, (state, { payload }) => {
state.isLoading = false
state.news = payload
})
.addCase(getShopNews.rejected, state => {
state.isLoading = false
})
}
})

export const { actions: shopNewsActions, reducer: shopNewsReducer } = shopNewsSlice
22 changes: 22 additions & 0 deletions src/widgets/NewsBlock/model/types/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export interface GetShopNewsResponse {
count: number
previous: string
next: string
results: ShopNewsData[]
}

export interface ShopNewsData {
id: number
title: string
text: string
image: string
pub_date: string
slug: string
meta_title: string
meta_description: string
}

export interface ShopNewsSchema {
isLoading: boolean
news: ShopNewsData[]
}
18 changes: 14 additions & 4 deletions src/widgets/NewsBlock/ui/NewsBlock.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
import { FC } from 'react'
import { FC, useEffect } from 'react'
import IconLink from '@/assets/icons/IconLink'
import Heading, { HeadingType } from '@/shared/ui/Heading/Heading'
import Link from '@/shared/ui/Link/Link'
import styles from './NewsBlock.module.scss'
import NewsCard from '@/entities/NewsCard/NewsCard'
import { newsData } from '@/mockData/newsData'
import Scroll from '@/shared/ui/Scroll/Scroll'
import { useAppDispatch } from '@/shared/libs/hooks/store'
import { getShopNewsSelector } from '../model/selectors/selectors'
import { useSelector } from 'react-redux'
import { getShopNews } from '../model/services/getShopNews'

/**
* Блок группы новостей
*/
const NewsBlock: FC = () => {
const dispatch = useAppDispatch()
const news = useSelector(getShopNewsSelector)

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

return (
<section className={styles.wrapper}>
<article>
Expand All @@ -21,8 +31,8 @@ const NewsBlock: FC = () => {
</Link>
</article>
<Scroll>
{newsData.map(item => (
<NewsCard key={item.id} card={item} />
{news.map(item => (
<NewsCard key={item.id} id={item.id} image={item.image} date={item.pub_date} title={item.title} />
))}
</Scroll>
</section>
Expand Down

0 comments on commit dbf6710

Please sign in to comment.