Skip to main content

Overview

The application layer provides React hooks that encapsulate business logic and state management. These hooks provide a clean interface for components to interact with order data and theme state.

useOrders

The primary hook for accessing and managing the global order state. Provides access to all orders, status-grouped orders, and order update functionality. Source: contexts/Orders.context.tsx:108

Signature

function useOrders(): {
  orders: OrderListDto[];
  updateOrderStatus: (id: string, status: OrderStatus) => Promise<void>;
  ordersByStatus: Record<OrderStatus, OrderListDto[]>;
  isLoading: boolean;
  error: string | null;
}

Returns

orders
OrderListDto[]
Array of all orders in the system
updateOrderStatus
function
Async function to update an order’s status with optimistic UI updatesParameters:
  • id (string): Order ID to update
  • status (OrderStatus): New status to set
ordersByStatus
Record<OrderStatus, OrderListDto[]>
Orders grouped by their status for easy rendering in columns
isLoading
boolean
true during initial order load, false after orders are loaded
error
string | null
Error message if initial load fails, or null if no error

Usage

import { useOrders } from '@/contexts/Orders.context';

function OrderBoard() {
  const { ordersByStatus, updateOrderStatus, isLoading, error } = useOrders();
  
  if (isLoading) return <div>Loading orders...</div>;
  if (error) return <div>Error: {error}</div>;
  
  return (
    <div className="board">
      {Object.entries(ordersByStatus).map(([status, orders]) => (
        <Column key={status} status={status}>
          {orders.map(order => (
            <OrderCard 
              key={order.id} 
              order={order}
              onStatusChange={(newStatus) => updateOrderStatus(order.id, newStatus)}
            />
          ))}
        </Column>
      ))}
    </div>
  );
}
The useOrders hook must be used within an OrdersProvider. It connects to real-time WebSocket updates automatically and implements optimistic UI updates with rollback on error.

useTheme

Hook for accessing and controlling the application theme (light/dark mode). Source: contexts/Theme.context.tsx:42

Signature

function useTheme(): {
  theme: "light" | "dark";
  toggleTheme: () => void;
}

Returns

theme
'light' | 'dark'
Current theme mode
toggleTheme
function
Function to toggle between light and dark themes

Usage

import { useTheme } from '@/contexts/Theme.context';

function ThemeToggle() {
  const { theme, toggleTheme } = useTheme();
  
  return (
    <button onClick={toggleTheme}>
      {theme === 'light' ? '🌙 Dark Mode' : '☀️ Light Mode'}
    </button>
  );
}
The useTheme hook must be used within a ThemeProvider. Theme preference is persisted to localStorage automatically.

useOrderDetail

A React hook that fetches and manages the state of a single order’s detailed information.

Signature

function useOrderDetail(orderId: string | null): {
  detail: OrderDetailDto | null;
  isLoading: boolean;
  error: string | null;
}

Parameters

orderId
string | null
required
The unique identifier of the order to fetch. Pass null to skip fetching.

Returns

detail
OrderDetailDto | null
The order detail data, or null if not yet loaded or if orderId is null
isLoading
boolean
true while the order details are being fetched, false otherwise
error
string | null
Error message if the fetch failed, or null if no error occurred

OrderDetailDto Structure

customerName
string
Name of the customer who placed the order
customerPhone
string
Phone number of the customer
deliveryAddress
string
Delivery address for the order
notes
string
Special instructions or notes for the order
courierName
string
Name of the assigned courier
items
array
required
Array of order items
id
string
required
Unique identifier for the item
name
string
required
Name of the item
image
string
required
URL to the item image
price
number
required
Price of a single unit
currency
string
required
Currency code (e.g., USD, EUR)
qty
number
required
Quantity ordered

Usage Examples

Basic Usage

import { useOrderDetail } from '@/application/hook/use-order-detail';

function OrderDetailPanel({ orderId }: { orderId: string }) {
  const { detail, isLoading, error } = useOrderDetail(orderId);
  
  if (isLoading) {
    return <div>Loading order details...</div>;
  }
  
  if (error) {
    return <div>Error: {error}</div>;
  }
  
  if (!detail) {
    return <div>No order found</div>;
  }
  
  return (
    <div>
      <h2>Order Details</h2>
      <p>Customer: {detail.customerName}</p>
      <p>Phone: {detail.customerPhone}</p>
      <p>Address: {detail.deliveryAddress}</p>
      {detail.notes && <p>Notes: {detail.notes}</p>}
      
      <h3>Items</h3>
      <ul>
        {detail.items.map(item => (
          <li key={item.id}>
            {item.name} - {item.qty} x {item.currency} {item.price}
          </li>
        ))}
      </ul>
    </div>
  );
}

Conditional Fetching

function OrderSidebar({ selectedOrderId }: { selectedOrderId: string | null }) {
  // Only fetches when selectedOrderId is not null
  const { detail, isLoading, error } = useOrderDetail(selectedOrderId);
  
  if (!selectedOrderId) {
    return <div>Select an order to view details</div>;
  }
  
  return (
    <div>
      {isLoading && <Spinner />}
      {error && <Alert type="error">{error}</Alert>}
      {detail && <OrderDetails data={detail} />}
    </div>
  );
}

With Loading States

function OrderInfo({ orderId }: { orderId: string }) {
  const { detail, isLoading, error } = useOrderDetail(orderId);
  
  return (
    <Card>
      {isLoading ? (
        <SkeletonLoader />
      ) : error ? (
        <ErrorMessage message={error} />
      ) : detail ? (
        <>
          <CustomerInfo
            name={detail.customerName}
            phone={detail.customerPhone}
            address={detail.deliveryAddress}
          />
          <OrderItems items={detail.items} />
          {detail.courierName && (
            <CourierInfo name={detail.courierName} />
          )}
        </>
      ) : null}
    </Card>
  );
}

Displaying Total Price

function OrderSummary({ orderId }: { orderId: string }) {
  const { detail, isLoading, error } = useOrderDetail(orderId);
  
  const totalPrice = detail?.items.reduce(
    (sum, item) => sum + (item.price * item.qty),
    0
  );
  
  const currency = detail?.items[0]?.currency;
  
  if (isLoading) return <div>Calculating...</div>;
  if (error) return <div>Error loading order</div>;
  
  return (
    <div>
      <h3>Order Total</h3>
      <p>{currency} {totalPrice?.toFixed(2)}</p>
    </div>
  );
}

Behavior Details

The hook implements automatic cleanup to prevent state updates on unmounted components. This prevents React warnings about memory leaks.

Automatic Refetch

The hook automatically refetches order details when the orderId parameter changes:
function OrderViewer() {
  const [currentOrderId, setCurrentOrderId] = useState<string | null>(null);
  
  // Automatically refetches when currentOrderId changes
  const { detail, isLoading } = useOrderDetail(currentOrderId);
  
  return (
    <div>
      <OrderSelector onSelect={setCurrentOrderId} />
      {detail && <OrderDetails data={detail} />}
    </div>
  );
}

Skipping Fetch

Passing null as the orderId skips the fetch entirely:
// No fetch occurs
const { detail } = useOrderDetail(null);
// detail will be null

Error Handling

The hook catches errors during fetch and provides them via the error field:
const { error } = useOrderDetail('invalid-id');

if (error) {
  // error will contain the error message
  console.error('Failed to load order:', error);
}

Implementation Notes

Dependencies

The hook depends on:
  • orderOrchestrator.getOrderDetail() from @/services/order.service
  • React’s useState and useEffect hooks

State Management

The hook manages three pieces of state:
  1. detail: The fetched order data
  2. isLoading: Loading indicator
  3. error: Error message if fetch fails

Cleanup

The hook implements proper cleanup using a cancellation flag:
useEffect(() => {
  let cancelled = false;
  
  // Fetch logic...
  
  return () => {
    cancelled = true; // Prevents state updates after unmount
  };
}, [orderId]);
This cleanup mechanism ensures that if the component unmounts or the orderId changes before the fetch completes, no state updates occur. This prevents “Can’t perform a React state update on an unmounted component” warnings.

Type Safety

// TypeScript infers the correct types
const { detail, isLoading, error } = useOrderDetail('order-123');

// detail is OrderDetailDto | null
if (detail) {
  // TypeScript knows detail is OrderDetailDto here
  console.log(detail.customerName); // ✓ Type-safe
  console.log(detail.invalidField);  // ✗ TypeScript error
}

// isLoading is boolean
if (isLoading) { /* ... */ }

// error is string | null
if (error) {
  console.log(error.toUpperCase()); // ✓ Type-safe
}

Build docs developers (and LLMs) love