All files / src/hooks useAddresses.ts

93.47% Statements 86/92
63.63% Branches 21/33
100% Functions 1/1
93.47% Lines 86/92

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 931x 1x 1x 1x 31x 31x 31x 31x 31x 14x 14x 14x 12x 12x 12x 12x 12x 14x 1x 14x 14x 14x 31x 31x 31x 16x 14x 14x 31x 31x 31x 3x 3x 2x 2x 2x 2x 2x 2x 3x 1x 1x 31x 31x 31x 1x 1x 1x 1x 1x 1x       1x       31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x 31x  
import { useState, useEffect, useCallback, useMemo } from "react";
import { clientLogger } from "@/lib/logging/clientLogger";
import { Address, UseAddressesReturn } from "@/types/user";
 
export function useAddresses(isAuthenticated: boolean): UseAddressesReturn {
  const [addresses, setAddresses] = useState<Address[]>([]);
  const [loading, setLoading] = useState(true);
 
  const fetchAddresses = useCallback(async () => {
    try {
      const response = await fetch("/api/user/addresses");
      if (response.ok) {
        const result = await response.json();
        // Handle both { data: [...] } and direct array responses
        const data = result?.data ?? result;
        setAddresses(Array.isArray(data) ? data : []);
      }
    } catch (error) {
      clientLogger.error("Failed to fetch addresses", error instanceof Error ? error : new Error(String(error)));
    } finally {
      setLoading(false);
    }
  }, []);
 
  useEffect(() => {
    if (isAuthenticated) {
      fetchAddresses();
    }
  }, [isAuthenticated, fetchAddresses]);
 
  const refreshAddresses = useCallback(async () => {
    try {
      const response = await fetch("/api/user/addresses");
      if (response.ok) {
        const result = await response.json();
        // Handle both { data: [...] } and direct array responses
        const data = result?.data ?? result;
        setAddresses(Array.isArray(data) ? data : []);
      }
    } catch (error) {
      clientLogger.error("Failed to refresh addresses", error instanceof Error ? error : new Error(String(error)));
    }
  }, []);
 
  const setAddressAsDefault = useCallback(async (addressId: number) => {
    try {
      const response = await fetch(`/api/user/addresses/${addressId}/set-default`, {
        method: "POST"});
      if (response.ok) {
        await refreshAddresses();
      } else {
        const error = await response.json();
        throw new Error(error.error || "Failed to set address as default");
      }
    } catch (error) {
      clientLogger.error("Failed to set address as default", error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }, [refreshAddresses]);
 
  // Filter addresses by type (with defensive check)
  const shippingAddresses = useMemo(
    () => (Array.isArray(addresses) ? addresses : []).filter(addr => addr.type === "SHIPPING"),
    [addresses]
  );
 
  const billingAddresses = useMemo(
    () => (Array.isArray(addresses) ? addresses : []).filter(addr => addr.type === "BILLING"),
    [addresses]
  );
 
  // Get default addresses (or first if no default)
  const defaultShippingAddress = useMemo(
    () => shippingAddresses.find(addr => addr.isDefault) || shippingAddresses[0],
    [shippingAddresses]
  );
 
  const defaultBillingAddress = useMemo(
    () => billingAddresses.find(addr => addr.isDefault) || billingAddresses[0],
    [billingAddresses]
  );
 
  return {
    addresses,
    loading,
    shippingAddresses,
    billingAddresses,
    defaultShippingAddress,
    defaultBillingAddress,
    refreshAddresses,
    setAddressAsDefault};
}