E-Commerce Development Overview
Building e-commerce applications with shopping carts, payment processing, inventory management, and order fulfillment.
Shopping Cart Cart State Management interface CartItem { productId: string; variantId?: string; quantity: number; price: number; name: string; image: string; }
interface Cart { id: string; items: CartItem[]; subtotal: number; tax: number; shipping: number; total: number; discountCode?: string; discountAmount: number; }
// Zustand cart store import { create } from 'zustand'; import { persist } from 'zustand/middleware';
interface CartStore {
cart: Cart;
addItem: (item: Omit
const useCartStore = create
addItem: (item, quantity = 1) => {
set((state) => {
const existingIndex = state.cart.items.findIndex(
(i) => i.productId === item.productId && i.variantId === item.variantId
);
const newItems = [...state.cart.items];
if (existingIndex >= 0) {
newItems[existingIndex].quantity += quantity;
} else {
newItems.push({ ...item, quantity });
}
return { cart: recalculateCart({ ...state.cart, items: newItems }) };
});
},
updateQuantity: (productId, quantity) => {
set((state) => {
if (quantity <= 0) {
return {
cart: recalculateCart({
...state.cart,
items: state.cart.items.filter((i) => i.productId !== productId),
}),
};
}
const newItems = state.cart.items.map((item) =>
item.productId === productId ? { ...item, quantity } : item
);
return { cart: recalculateCart({ ...state.cart, items: newItems }) };
});
},
removeItem: (productId) => {
set((state) => ({
cart: recalculateCart({
...state.cart,
items: state.cart.items.filter((i) => i.productId !== productId),
}),
}));
},
clearCart: () => set({ cart: createEmptyCart() }),
applyDiscount: async (code) => {
const discount = await validateDiscountCode(code);
set((state) => ({
cart: recalculateCart({
...state.cart,
discountCode: code,
discountAmount: discount.amount,
}),
}));
},
}),
{ name: 'cart-storage' }
) );
function recalculateCart(cart: Cart): Cart { const subtotal = cart.items.reduce( (sum, item) => sum + item.price * item.quantity, 0 ); const tax = subtotal * 0.1; // 10% tax const shipping = subtotal > 100 ? 0 : 9.99; const total = subtotal + tax + shipping - cart.discountAmount;
return { ...cart, subtotal, tax, shipping, total }; }
Payment Processing Stripe Integration import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { apiVersion: '2023-10-16', });
// Create checkout session
async function createCheckoutSession(cart: Cart, customerId?: string) {
const session = await stripe.checkout.sessions.create({
mode: 'payment',
customer: customerId,
line_items: cart.items.map((item) => ({
price_data: {
currency: 'usd',
product_data: {
name: item.name,
images: [item.image],
},
unit_amount: Math.round(item.price * 100),
},
quantity: item.quantity,
})),
discounts: cart.discountCode
? [{ coupon: cart.discountCode }]
: undefined,
shipping_address_collection: {
allowed_countries: ['US', 'CA', 'GB'],
},
success_url: ${process.env.APP_URL}/checkout/success?session_id={CHECKOUT_SESSION_ID},
cancel_url: ${process.env.APP_URL}/cart,
metadata: {
cartId: cart.id,
},
});
return session; }
// Create payment intent (for custom checkout) async function createPaymentIntent(amount: number, customerId?: string) { const paymentIntent = await stripe.paymentIntents.create({ amount: Math.round(amount * 100), currency: 'usd', customer: customerId, automatic_payment_methods: { enabled: true }, });
return { clientSecret: paymentIntent.client_secret, paymentIntentId: paymentIntent.id, }; }
// Webhook handler async function handleStripeWebhook(body: string, signature: string) { const event = stripe.webhooks.constructEvent( body, signature, process.env.STRIPE_WEBHOOK_SECRET! );
switch (event.type) { case 'checkout.session.completed': { const session = event.data.object as Stripe.Checkout.Session; await fulfillOrder(session); break; }
case 'payment_intent.succeeded': {
const paymentIntent = event.data.object as Stripe.PaymentIntent;
await handlePaymentSuccess(paymentIntent);
break;
}
case 'payment_intent.payment_failed': {
const paymentIntent = event.data.object as Stripe.PaymentIntent;
await handlePaymentFailure(paymentIntent);
break;
}
} }
React Stripe Elements import { loadStripe } from '@stripe/stripe-js'; import { Elements, PaymentElement, useStripe, useElements, } from '@stripe/react-stripe-js';
const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_KEY!);
function CheckoutForm({ clientSecret }: { clientSecret: string }) {
const stripe = useStripe();
const elements = useElements();
const [error, setError] = useState
const handleSubmit = async (e: React.FormEvent) => { e.preventDefault();
if (!stripe || !elements) return;
setProcessing(true);
setError(null);
const { error: submitError } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: `${window.location.origin}/checkout/success`,
},
});
if (submitError) {
setError(submitError.message || 'Payment failed');
setProcessing(false);
}
};
return (
); }function CheckoutPage() { const [clientSecret, setClientSecret] = useState('');
useEffect(() => { fetch('/api/create-payment-intent', { method: 'POST', body: JSON.stringify({ amount: cart.total }), }) .then((res) => res.json()) .then((data) => setClientSecret(data.clientSecret)); }, []);
if (!clientSecret) return
return (
Inventory Management interface Product { id: string; name: string; sku: string; price: number; inventory: number; lowStockThreshold: number; variants: ProductVariant[]; }
interface ProductVariant {
id: string;
name: string;
sku: string;
price: number;
inventory: number;
attributes: Record
// Inventory operations with optimistic locking
async function reserveInventory(items: CartItem[]): Promise
if (!product || product.inventory < item.quantity) {
throw new Error(`Insufficient inventory for ${item.name}`);
}
// Optimistic locking with version check
const updated = await tx.product.updateMany({
where: {
id: item.productId,
version: product.version,
inventory: { gte: item.quantity },
},
data: {
inventory: { decrement: item.quantity },
version: { increment: 1 },
},
});
if (updated.count === 0) {
throw new Error(`Concurrent modification for ${item.name}`);
}
}
return true;
}); }
// Release inventory (on order cancellation) async function releaseInventory(orderId: string) { const order = await prisma.order.findUnique({ where: { id: orderId }, include: { items: true }, });
await prisma.$transaction( order.items.map((item) => prisma.product.update({ where: { id: item.productId }, data: { inventory: { increment: item.quantity } }, }) ) ); }
// Low stock alerts async function checkLowStock() { const lowStockProducts = await prisma.product.findMany({ where: { inventory: { lte: prisma.product.fields.lowStockThreshold }, }, });
for (const product of lowStockProducts) { await sendLowStockAlert(product); } }
Order Management enum OrderStatus { PENDING = 'pending', PAID = 'paid', PROCESSING = 'processing', SHIPPED = 'shipped', DELIVERED = 'delivered', CANCELLED = 'cancelled', REFUNDED = 'refunded', }
interface Order { id: string; userId: string; status: OrderStatus; items: OrderItem[]; subtotal: number; tax: number; shipping: number; total: number; shippingAddress: Address; billingAddress: Address; paymentIntentId: string; trackingNumber?: string; createdAt: Date; updatedAt: Date; }
// Create order from checkout session async function fulfillOrder(session: Stripe.Checkout.Session) { const order = await prisma.order.create({ data: { userId: session.client_reference_id!, status: OrderStatus.PAID, paymentIntentId: session.payment_intent as string, subtotal: session.amount_subtotal! / 100, total: session.amount_total! / 100, shippingAddress: JSON.parse(session.metadata!.shippingAddress), items: { create: JSON.parse(session.metadata!.items), }, }, });
// Reserve inventory await reserveInventory(order.items);
// Send confirmation email await sendOrderConfirmation(order);
// Notify fulfillment system await notifyFulfillment(order);
return order; }
// Order status updates async function updateOrderStatus(orderId: string, status: OrderStatus) { const order = await prisma.order.update({ where: { id: orderId }, data: { status }, });
// Send notification await sendOrderStatusUpdate(order);
return order; }
Product Catalog // Product search with filters async function searchProducts(params: { query?: string; category?: string; minPrice?: number; maxPrice?: number; sortBy?: 'price' | 'name' | 'createdAt'; sortOrder?: 'asc' | 'desc'; page?: number; limit?: number; }) { const { query, category, minPrice, maxPrice, sortBy = 'createdAt', sortOrder = 'desc', page = 1, limit = 20, } = params;
const where: Prisma.ProductWhereInput = { status: 'active', ...(query && { OR: [ { name: { contains: query, mode: 'insensitive' } }, { description: { contains: query, mode: 'insensitive' } }, ], }), ...(category && { categoryId: category }), ...(minPrice && { price: { gte: minPrice } }), ...(maxPrice && { price: { lte: maxPrice } }), };
const [products, total] = await Promise.all([ prisma.product.findMany({ where, orderBy: { [sortBy]: sortOrder }, skip: (page - 1) * limit, take: limit, include: { category: true, images: true, variants: true, }, }), prisma.product.count({ where }), ]);
return { products, pagination: { page, limit, total, totalPages: Math.ceil(total / limit), }, }; }
Related Skills [[payment-processing]] - Payment systems [[backend]] - API development [[database]] - Data modeling