Untitled
unknown
javascript
7 months ago
5.9 kB
3
Indexable
Never
import { createSlice, createAsyncThunk, createEntityAdapter, PayloadAction, } from '@reduxjs/toolkit'; import { getMerchantBasket, addToMerchantBasket, updateMerchantBasketLineQty, applyMerchantBasketCoupon, removeMerchantBasketVoucher, getBasketsApi, } from 'api/index'; import { Basket, BasketLine, Product } from 'api/models'; import * as Analytics from 'utils/analytics'; import { RootState } from '../store'; type ThunkApiType = { state: RootState }; export const fetchMerchantBasket = createAsyncThunk<Basket, number | string>( 'basket/fetch', async (merchantId) => { const result = await getMerchantBasket({ merchantId }); return result.data as Basket; }, ); interface AddToBasketParams { productId: number | string; merchantId: number | string; quantity: number; } export const addToBasket = createAsyncThunk<Basket, AddToBasketParams, ThunkApiType>( 'basket/add', async ({ productId, merchantId, quantity }) => { const payload = { merchantId, productId, quantity }; Analytics.logEvent('BASKET_ADD_TO', payload); const result = await addToMerchantBasket(payload); return result.data as Basket; }, ); export const getBaskets = createAsyncThunk('baskets/getBaskets', async (_, { dispatch }) => { const results = await getBasketsApi(); return results.data as Basket[]; }); interface UpdateQtyParams { lineId: number | string; productId: number | string; merchantId: number | string; quantity: number; } export const updateLineQty = createAsyncThunk<Basket, UpdateQtyParams, ThunkApiType>( 'basket/update', async ({ lineId, productId, merchantId, quantity }) => { Analytics.logEvent('BASKET_UPDATE_LINE_QTY', { merchantId, productId, quantity, }); const result = await updateMerchantBasketLineQty({ merchantId, lineId, quantity, }); return result.data as Basket; }, ); interface RemoveBasketLineParams { lineId: number | string; productId: number | string; merchantId: number | string; } export const removeBasketLine = createAsyncThunk<Basket, RemoveBasketLineParams, ThunkApiType>( 'basket/removeLine', async ({ lineId, productId, merchantId }) => { Analytics.logEvent('BASKET_UPDATE_LINE_QTY', { merchantId, productId, }); const result = await updateMerchantBasketLineQty({ merchantId, lineId, quantity: 0, }); return result.data as Basket; }, ); export const applyVoucher = createAsyncThunk< Basket, { code: string; merchantId: number }, ThunkApiType >('basket/applyVoucher', async ({ code, merchantId }) => { const results = await applyMerchantBasketCoupon({ merchantId, code }); return results.data as Basket; }); export const removeVoucher = createAsyncThunk< Basket, { voucherId: string | number; merchantId: number }, ThunkApiType >('basket/removeVoucher', async ({ voucherId, merchantId }) => { const results = await removeMerchantBasketVoucher({ merchantId, voucherId }); return results.data as Basket; }); /* Utility */ const updateBasket = (state: any, { payload }: PayloadAction<Basket>) => { const basketIndex = state.baskets.findIndex((basket: Basket) => basket.id === payload.id); if (basketIndex !== -1) { const updatedBaskets = [...state.baskets]; updatedBaskets[basketIndex] = payload; state.baskets = updatedBaskets; basketAdapter.setAll(state, payload.allLines); } }; export const basketAdapter = createEntityAdapter<Basket>(); type InitialStateType = { fetchStatus: 'idle' | 'pending' | 'fulfilled'; baskets: Basket[]; stagedProduct?: Product; }; const initialState = basketAdapter.getInitialState<InitialStateType>({ fetchStatus: 'idle', baskets: [], stagedProduct: undefined, }); export const basketSlice = createSlice({ name: 'basket', initialState, reducers: { resetBasket(state) { state.fetchStatus = 'idle'; state.baskets = []; basketAdapter.removeAll(state); }, setStagedProduct(state, { payload }) { state.stagedProduct = payload; }, resetStagedProduct(state) { state.stagedProduct = undefined; }, }, extraReducers: (builder) => { builder.addCase(getBaskets.pending, (state) => { state.fetchStatus = 'pending'; }); builder.addCase(getBaskets.fulfilled, (state, { payload }) => { state.fetchStatus = 'fulfilled'; state.baskets = payload; basketAdapter.setAll(state, payload); }); builder.addCase(getBaskets.rejected, (state) => { state.fetchStatus = 'fulfilled'; }); builder.addCase(addToBasket.fulfilled, updateBasket); builder.addCase(updateLineQty.fulfilled, updateBasket); builder.addCase(removeBasketLine.fulfilled, updateBasket); builder.addCase(applyVoucher.fulfilled, updateBasket); builder.addCase(removeVoucher.fulfilled, updateBasket); }, }); export const { resetBasket, setStagedProduct, resetStagedProduct } = basketSlice.actions; export default basketSlice.reducer; // Selectors export const { selectById: selectBasketById, selectIds: selectBasketIds, selectEntities: selectBaskets, selectAll: selectAllBaskets, selectTotal: selectTotalBaskets, } = basketAdapter.getSelectors((state: RootState) => state.basket); export const selectAllLinesForBasket = (state: RootState, basketId: number): BasketLine[] => { const basket = selectBasketById(state, basketId); return basket?.allLines ?? []; }; // export const selectBasketMerchantId = (state: RootState) => state.basket?.partner.id; export const selectBasketsFetchStatus = (state: RootState) => state.basket.fetchStatus; export const selectBasketStagedProduct = (state: RootState) => state.basket.stagedProduct; export const getProductsQty = (basketLines: BasketLine[]) => { return basketLines.reduce((res: any, line) => { res[line.product.id] = line.quantity; return res; }, {}); };
Leave a Comment