112 lines
3.8 KiB
TypeScript
112 lines
3.8 KiB
TypeScript
import { createReducer } from '@reduxjs/toolkit';
|
|
import { CartItem, MerchantCartGroup } from '@interfaces/cart';
|
|
import { addToCartThunk, getCartThunk, updateCartItemThunk } from './thunk';
|
|
|
|
// ─── State ───────────────────────────────────────────────────────────────────
|
|
|
|
export interface CartState {
|
|
id: string | null;
|
|
customerId: string | null;
|
|
items: CartItem[];
|
|
groupedByMerchant: MerchantCartGroup[];
|
|
subtotal: number;
|
|
totalItems: number;
|
|
isLoading: boolean;
|
|
error: string | null;
|
|
}
|
|
|
|
const initialState: CartState = {
|
|
id: null,
|
|
customerId: null,
|
|
items: [],
|
|
groupedByMerchant: [],
|
|
subtotal: 0,
|
|
totalItems: 0,
|
|
isLoading: false,
|
|
error: null,
|
|
};
|
|
|
|
// ─── Selector ────────────────────────────────────────────────────────────────
|
|
|
|
export const selectCartTotal = (state: { cart: CartState }) => {
|
|
const subtotal = state.cart.subtotal || 0;
|
|
const deliveryFee = 40; // Flat fee for now
|
|
const platformFee = 10; // Flat fee for now
|
|
const discount = 0; // Removing discount logic for now as requested
|
|
return {
|
|
subtotal,
|
|
deliveryFee,
|
|
platformFee,
|
|
discount,
|
|
total: Math.max(0, subtotal + deliveryFee + platformFee - discount),
|
|
itemCount: state.cart.totalItems || 0,
|
|
};
|
|
};
|
|
|
|
// ─── Reducer ─────────────────────────────────────────────────────────────────
|
|
|
|
const cartReducer = createReducer(initialState, builder => {
|
|
builder
|
|
// getCartThunk
|
|
.addCase(getCartThunk.pending, state => {
|
|
state.isLoading = true;
|
|
state.error = null;
|
|
})
|
|
.addCase(getCartThunk.fulfilled, (state, action) => {
|
|
state.isLoading = false;
|
|
const cart = action.payload;
|
|
state.id = cart.id;
|
|
state.customerId = cart.customerId;
|
|
state.items = cart.items || [];
|
|
state.groupedByMerchant = cart.groupedByMerchant || [];
|
|
state.subtotal = cart.subtotal || 0;
|
|
state.totalItems = cart.totalItems || 0;
|
|
})
|
|
.addCase(getCartThunk.rejected, (state, action) => {
|
|
state.isLoading = false;
|
|
state.error = (action.payload as string) || 'Failed to get cart';
|
|
})
|
|
|
|
// addToCartThunk
|
|
.addCase(addToCartThunk.pending, state => {
|
|
state.isLoading = true;
|
|
state.error = null;
|
|
})
|
|
.addCase(addToCartThunk.fulfilled, (state, action) => {
|
|
state.isLoading = false;
|
|
const cart = action.payload;
|
|
state.id = cart.id;
|
|
state.customerId = cart.customerId;
|
|
state.items = cart.items || [];
|
|
state.groupedByMerchant = cart.groupedByMerchant || [];
|
|
state.subtotal = cart.subtotal || 0;
|
|
state.totalItems = cart.totalItems || 0;
|
|
})
|
|
.addCase(addToCartThunk.rejected, (state, action) => {
|
|
state.isLoading = false;
|
|
state.error = (action.payload as string) || 'Failed to add to cart';
|
|
})
|
|
|
|
// updateCartItemThunk
|
|
.addCase(updateCartItemThunk.pending, state => {
|
|
state.isLoading = true;
|
|
state.error = null;
|
|
})
|
|
.addCase(updateCartItemThunk.fulfilled, (state, action) => {
|
|
state.isLoading = false;
|
|
const cart = action.payload;
|
|
state.id = cart.id;
|
|
state.customerId = cart.customerId;
|
|
state.items = cart.items || [];
|
|
state.groupedByMerchant = cart.groupedByMerchant || [];
|
|
state.subtotal = cart.subtotal || 0;
|
|
state.totalItems = cart.totalItems || 0;
|
|
})
|
|
.addCase(updateCartItemThunk.rejected, (state, action) => {
|
|
state.isLoading = false;
|
|
state.error = (action.payload as string) || 'Failed to update cart item';
|
|
});
|
|
});
|
|
|
|
export default cartReducer;
|