You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
78 lines
2.4 KiB
TypeScript
78 lines
2.4 KiB
TypeScript
import { createAsyncThunk, createSlice, type PayloadAction, createSelector } from '@reduxjs/toolkit'
|
|
import type { RootState, ThunkApi } from '../store'
|
|
import type { Product } from '../types'
|
|
import type { ResponseData } from '../network'
|
|
|
|
interface AddBasketAction {
|
|
id: number
|
|
count: number
|
|
}
|
|
|
|
interface ShopState {
|
|
products: Product[]
|
|
loading: boolean
|
|
error?: string
|
|
}
|
|
|
|
const initialState: ShopState = {
|
|
products: [],
|
|
loading: false,
|
|
error: undefined,
|
|
}
|
|
|
|
export const shopSlice = createSlice({
|
|
name: 'shop',
|
|
initialState,
|
|
reducers: {
|
|
// TODO: дописать action.payload.id
|
|
addToBasket: (state, action: PayloadAction<AddBasketAction>) => {
|
|
state.products[0].count -= action.payload.count
|
|
state.products[0].reserved += action.payload.count
|
|
},
|
|
},
|
|
extraReducers: builder => {
|
|
builder
|
|
.addCase(fetchProducts.pending, state => {
|
|
state.loading = true
|
|
state.error = undefined
|
|
})
|
|
.addCase(fetchProducts.fulfilled, (state, action) => {
|
|
state.products = action.payload.success as Product[]
|
|
state.loading = false
|
|
})
|
|
.addCase(fetchProducts.rejected, (state, action) => {
|
|
state.loading = false
|
|
if (action.payload) {
|
|
state.error = (action.payload as ResponseData).error
|
|
} else {
|
|
state.error = action.error.message
|
|
}
|
|
})
|
|
},
|
|
})
|
|
|
|
export const { addToBasket } = shopSlice.actions
|
|
|
|
export const selectShopLoading = (state: RootState) => state.shop.loading
|
|
export const selectShopError = (state: RootState) => state.shop.error
|
|
export const selectProducts = (state: RootState) => state.shop.products
|
|
|
|
export const selectProduct = (productId: number) =>
|
|
createSelector([selectProducts], products => {
|
|
return products.find(product => product.id === productId)
|
|
})
|
|
|
|
export const shopReducer = shopSlice.reducer
|
|
|
|
export const fetchProducts = createAsyncThunk<ResponseData, void, ThunkApi>(
|
|
'products/fetchProducts',
|
|
async (_, { fulfillWithValue, rejectWithValue, extra: networkApi }) => {
|
|
try {
|
|
const data = await networkApi.request<ResponseData>('/shop/')
|
|
return fulfillWithValue(data)
|
|
} catch (error) {
|
|
return rejectWithValue(error)
|
|
}
|
|
}
|
|
)
|