115 lines
3.7 KiB
TypeScript
115 lines
3.7 KiB
TypeScript
import { createAction, createReducer } from '@reduxjs/toolkit';
|
|
import { CartItem, CatalogItem } from '../../../interfaces';
|
|
|
|
// ─── State ───────────────────────────────────────────────────────────────────
|
|
|
|
export interface CartState {
|
|
items: CartItem[];
|
|
couponCode: string | null;
|
|
discount: number;
|
|
providerId: string | null;
|
|
providerName: string | null;
|
|
}
|
|
|
|
const initialState: CartState = {
|
|
items: [],
|
|
couponCode: null,
|
|
discount: 0,
|
|
providerId: null,
|
|
providerName: null,
|
|
};
|
|
|
|
// ─── Actions ─────────────────────────────────────────────────────────────────
|
|
|
|
export const addItem = createAction<{
|
|
providerId: string;
|
|
providerName: string;
|
|
item: CatalogItem;
|
|
}>('cart/addItem');
|
|
|
|
export const removeItem = createAction<string>('cart/removeItem');
|
|
export const clearCart = createAction('cart/clearCart');
|
|
export const applyCoupon = createAction<string>('cart/applyCoupon');
|
|
export const removeCoupon = createAction('cart/removeCoupon');
|
|
|
|
// ─── Selector ────────────────────────────────────────────────────────────────
|
|
|
|
export const selectCartTotal = (state: { cart: CartState }) => {
|
|
const subtotal = state.cart.items.reduce(
|
|
(sum, item) => sum + item.item.price * item.quantity,
|
|
0,
|
|
);
|
|
const deliveryFee = 40;
|
|
const platformFee = 10;
|
|
const discount = state.cart.discount;
|
|
return {
|
|
subtotal,
|
|
deliveryFee,
|
|
platformFee,
|
|
discount,
|
|
total: Math.max(0, subtotal + deliveryFee + platformFee - discount),
|
|
itemCount: state.cart.items.reduce((sum, item) => sum + item.quantity, 0),
|
|
};
|
|
};
|
|
|
|
// ─── Reducer ─────────────────────────────────────────────────────────────────
|
|
|
|
const cartReducer = createReducer(initialState, builder => {
|
|
builder
|
|
.addCase(addItem, (state, action) => {
|
|
const { providerId, providerName, item } = action.payload;
|
|
|
|
// Clear cart if switching providers
|
|
if (state.providerId && state.providerId !== providerId) {
|
|
state.items = [];
|
|
}
|
|
|
|
state.providerId = providerId;
|
|
state.providerName = providerName;
|
|
|
|
const existing = state.items.find(i => i.item.id === item.id);
|
|
if (existing) {
|
|
existing.quantity += 1;
|
|
} else {
|
|
state.items.push({
|
|
id: `${providerId}-${item.id}`,
|
|
providerId,
|
|
providerName,
|
|
item,
|
|
quantity: 1,
|
|
});
|
|
}
|
|
})
|
|
.addCase(removeItem, (state, action) => {
|
|
const existing = state.items.find(i => i.item.id === action.payload);
|
|
if (existing) {
|
|
if (existing.quantity > 1) {
|
|
existing.quantity -= 1;
|
|
} else {
|
|
state.items = state.items.filter(i => i.item.id !== action.payload);
|
|
}
|
|
}
|
|
if (state.items.length === 0) {
|
|
state.providerId = null;
|
|
state.providerName = null;
|
|
}
|
|
})
|
|
.addCase(clearCart, state => {
|
|
state.items = [];
|
|
state.couponCode = null;
|
|
state.discount = 0;
|
|
state.providerId = null;
|
|
state.providerName = null;
|
|
})
|
|
.addCase(applyCoupon, (state, action) => {
|
|
state.couponCode = action.payload;
|
|
state.discount = 50;
|
|
})
|
|
.addCase(removeCoupon, state => {
|
|
state.couponCode = null;
|
|
state.discount = 0;
|
|
});
|
|
});
|
|
|
|
export default cartReducer;
|