Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | // API client functions for shopping cart
import { getOrCreateDeviceId } from '../device-id';
import { CartItem } from '@/redux/features/cartSlice';
import { clientLogger } from '@/lib/logging/clientLogger';
/**
* Helper to extract data from API response
*/
function extractData<T>(result: { success?: boolean; data?: T } | T): T {
if (result && typeof result === 'object' && 'data' in result) {
return result.data as T;
}
return result as T;
}
/**
* Get common headers with device ID
*/
function getHeaders(): HeadersInit {
const deviceId = getOrCreateDeviceId();
return {
'x-device-id': deviceId};
}
/**
* Fetch user's cart items
*/
export async function getCart(): Promise<CartItem[]> {
const response = await fetch("/api/cart", {
headers: getHeaders()
});
if (!response.ok) {
const errorText = await response.text();
clientLogger.error('[CartAPI] Error response', undefined, {
category: 'EXTERNAL',
errorText,
});
throw new Error("Failed to fetch cart");
}
const result = await response.json();
const data = extractData<{ items?: CartItem[] } | CartItem[]>(result);
// Handle both { items: [...] } and direct array responses
if (data && typeof data === 'object' && 'items' in data) {
return Array.isArray(data.items) ? data.items : [];
}
return Array.isArray(data) ? data : [];
}
/**
* Add item to cart
*/
export async function addToCart(productId: number, quantity: number): Promise<CartItem> {
const response = await fetch("/api/cart", {
method: "POST",
headers: {
"Content-Type": "application/json",
...getHeaders()},
body: JSON.stringify({ productId, quantity })});
if (!response.ok) {
throw new Error("Failed to add to cart");
}
const result = await response.json();
return extractData<CartItem>(result);
}
/**
* Update cart item quantity
*/
export async function updateCartItem(productId: number, quantity: number): Promise<CartItem> {
const response = await fetch(`/api/cart/${productId}`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
...getHeaders()},
body: JSON.stringify({ quantity })});
if (!response.ok) {
throw new Error("Failed to update cart item");
}
const result = await response.json();
return extractData<CartItem>(result);
}
/**
* Remove item from cart
*/
export async function removeFromCart(productId: number): Promise<{ message: string }> {
const response = await fetch(`/api/cart/${productId}`, {
method: "DELETE",
headers: getHeaders()});
if (!response.ok) {
throw new Error("Failed to remove from cart");
}
const result = await response.json();
return extractData<{ message: string }>(result);
}
|