All files / src/lib/api cart.ts

30.76% Statements 32/104
100% Branches 0/0
0% Functions 0/6
30.76% Lines 32/104

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 1051x 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);
}