chore: transfer repo
This commit is contained in:
180
components/cart/CartPage.tsx
Normal file
180
components/cart/CartPage.tsx
Normal file
@@ -0,0 +1,180 @@
|
||||
'use client';
|
||||
|
||||
import { container } from '@/lib/utils';
|
||||
import { useCart } from 'components/cart/cart-context';
|
||||
import { useTransition } from 'react';
|
||||
import { removeItem, updateItemQuantity } from './actions';
|
||||
import { CartDiscountForm } from './CartDiscountForm';
|
||||
import { CartSummary } from './CartSummary';
|
||||
import { EmptyCartMessage } from './EmptyCartMessage';
|
||||
import { useCartProcessing } from './hooks/useCartProcessing';
|
||||
import { BoxesSection } from './sections/BoxesSection';
|
||||
import { CartHeader } from './sections/CartHeader';
|
||||
import { CartLoading } from './sections/CartLoading';
|
||||
import { OrderNotes } from './sections/OrderNotes';
|
||||
import { ProductsSection } from './sections/ProductsSection';
|
||||
|
||||
export default function CartPage() {
|
||||
const { cart, updateCartItem } = useCart();
|
||||
const [isPending, startTransition] = useTransition();
|
||||
const { boxes, standaloneProducts, isGroupingComplete, didInitialProcess } = useCartProcessing(cart);
|
||||
|
||||
if (!cart?.lines.length) {
|
||||
return <EmptyCartMessage />;
|
||||
}
|
||||
|
||||
// Show loading state while processing cart items
|
||||
if (!didInitialProcess || !isGroupingComplete) {
|
||||
return <CartLoading />;
|
||||
}
|
||||
|
||||
const handleUpdateCartItem = (merchandiseId: string, updateType: 'plus' | 'minus' | 'delete', itemId?: string) => {
|
||||
// First update the client-side cart state for immediate feedback
|
||||
updateCartItem(merchandiseId, updateType, itemId);
|
||||
|
||||
// Update lastBoxState in localStorage if this is a box item
|
||||
try {
|
||||
const boxStateString = localStorage.getItem('lastBoxState');
|
||||
if (boxStateString) {
|
||||
const boxState = JSON.parse(boxStateString);
|
||||
|
||||
// Check if this item belongs to a box
|
||||
const cartItem = cart.lines.find(item => {
|
||||
if (itemId && item.id) {
|
||||
return item.id === itemId;
|
||||
}
|
||||
return item.merchandise.id === merchandiseId;
|
||||
});
|
||||
|
||||
if (cartItem) {
|
||||
// Check if it's a box item by looking at attributes
|
||||
const attrs = cartItem.attributes || [];
|
||||
const boxType = attrs.find(attr => attr.key === '_box_type')?.value;
|
||||
const boxGroupId = attrs.find(attr => attr.key === '_box_group_id')?.value;
|
||||
|
||||
if (boxType && boxGroupId) {
|
||||
// Find the corresponding item in the stored state
|
||||
if (boxType === 'item' && boxState.productItems) {
|
||||
if (updateType === 'delete') {
|
||||
// Remove the item from productItems
|
||||
boxState.productItems = boxState.productItems.filter((item: { id: string, variantId: string }) =>
|
||||
item.id !== cartItem.merchandise.product.id ||
|
||||
item.variantId !== cartItem.merchandise.id
|
||||
);
|
||||
} else {
|
||||
// Update quantity
|
||||
const productItem = boxState.productItems.find((item: { id: string, variantId: string }) =>
|
||||
item.id === cartItem.merchandise.product.id &&
|
||||
item.variantId === cartItem.merchandise.id
|
||||
);
|
||||
|
||||
if (productItem) {
|
||||
const newQuantity = updateType === 'plus'
|
||||
? cartItem.quantity + 1
|
||||
: Math.max(1, cartItem.quantity - 1);
|
||||
productItem.quantity = newQuantity;
|
||||
}
|
||||
}
|
||||
|
||||
// Save updated state back to localStorage
|
||||
localStorage.setItem('lastBoxState', JSON.stringify(boxState));
|
||||
}
|
||||
else if (boxType === 'container' && boxState.boxItems) {
|
||||
if (updateType === 'delete') {
|
||||
// Remove the box
|
||||
boxState.boxItems = boxState.boxItems.filter((item: { id: string }) =>
|
||||
item.id !== cartItem.merchandise.product.id
|
||||
);
|
||||
} else {
|
||||
// Update quantity
|
||||
const boxItem = boxState.boxItems.find((item: { id: string }) =>
|
||||
item.id === cartItem.merchandise.product.id
|
||||
);
|
||||
|
||||
if (boxItem) {
|
||||
const newQuantity = updateType === 'plus'
|
||||
? cartItem.quantity + 1
|
||||
: Math.max(1, cartItem.quantity - 1);
|
||||
boxItem.quantity = newQuantity;
|
||||
}
|
||||
}
|
||||
|
||||
// Save updated state back to localStorage
|
||||
localStorage.setItem('lastBoxState', JSON.stringify(boxState));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error updating box state in localStorage', error);
|
||||
}
|
||||
|
||||
// Then update the server-side cart
|
||||
startTransition(() => {
|
||||
if (updateType === 'delete') {
|
||||
// Call server action to remove item
|
||||
removeItem({}, merchandiseId, itemId);
|
||||
} else {
|
||||
// Find the specific item to update, using both merchandise ID and item ID if provided
|
||||
let item = cart.lines.find((item: { id?: string, merchandise: { id: string } }) => {
|
||||
if (itemId && item.id) {
|
||||
// If we have item ID, use it for more specific matching
|
||||
return item.id === itemId;
|
||||
}
|
||||
// Fall back to merchandise ID only
|
||||
return item.merchandise.id === merchandiseId;
|
||||
});
|
||||
|
||||
if (item) {
|
||||
// Calculate new quantity based on the updateType
|
||||
const newQuantity = updateType === 'plus'
|
||||
? item.quantity + 1
|
||||
: Math.max(1, item.quantity - 1);
|
||||
|
||||
// Call server action to update quantity
|
||||
updateItemQuantity({}, { merchandiseId, quantity: newQuantity, itemId });
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={container}>
|
||||
<div className="pb-20">
|
||||
<div className="flex flex-col lg:flex-row lg:justify-between gap-8">
|
||||
{/* Left Side: Cart Items */}
|
||||
<div className="lg:w-[62%]">
|
||||
<CartHeader totalQuantity={cart.totalQuantity} />
|
||||
|
||||
{/* Boxes Section */}
|
||||
<BoxesSection
|
||||
boxes={boxes}
|
||||
onUpdate={handleUpdateCartItem}
|
||||
isPending={isPending}
|
||||
/>
|
||||
|
||||
{/* Standalone Products Section */}
|
||||
<ProductsSection
|
||||
products={standaloneProducts}
|
||||
onUpdate={handleUpdateCartItem}
|
||||
isPending={isPending}
|
||||
/>
|
||||
|
||||
{/* Order Notes */}
|
||||
<OrderNotes />
|
||||
|
||||
{/* Discount Form */}
|
||||
<CartDiscountForm />
|
||||
</div>
|
||||
|
||||
{/* Right Side: Order Summary */}
|
||||
<div className="lg:w-[30%]">
|
||||
<div className="mt-6 lg:mt-[72px]">
|
||||
<CartSummary cart={cart} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user