Skip to content
Twilight React Playground
ثيم رائدaren

order

objectBeginnerserverbrowserlive demo

The signed-in customer's orders: a filterable list, one order's details, its shipments and ratings, and the thank-you text after checkout.

import { order, OrdersListParams, OrdersListResponse, OrderDetailResponse, CheckoutThankYouData } from '@salla.sa/twilight-theme-engine/api/order';

In plain words

Account pages show a customer their past orders. order.list() returns them (optionally only the pending ones), order.find(id) returns one order in full, and order.shipments(id) and order.ratings(id) return what shipped and what was rated.

All of these belong to one customer, so they need a signed-in shopper. For a guest the API refuses; keep the query switched off until there is a token.

Signature

order.list(params?: OrdersListParams): Promise<OrdersListResponse>
order.find(id: string): Promise<OrderDetailResponse>              // { order: Order }
order.findOrThrow(id: string): Promise<OrderDetailResponse>       // 401/403 → unauthorized(); others rethrown
order.shipments(orderId: string): Promise<OrderShipmentItem[]>
order.ratings(orderId: string): Promise<OrderRatingItem[]>
order.thankYou(orderId: string): Promise<CheckoutThankYouData>
order.thankYouOrThrow(orderId: string): Promise<CheckoutThankYouData>   // any failure → NotFoundError

order.queries.list(params?)       // key ['orders', 'list', params]
order.queries.find(id)            // key ['orders', 'detail', id]
order.queries.shipments(orderId)  // key ['orders', 'shipments', orderId]
order.queries.ratings(orderId)    // key ['orders', 'ratings', orderId]
order.queries.thankYou(orderId)   // key ['orders', 'thankYou', orderId]

interface OrdersListParams {
  page?: number;
  cursor?: string | null;
  status?: string;
  feedback_status?: string;
  with_items?: boolean | number;    // truthy → each order's items[]
  signal?: AbortSignal;
}
interface OrdersListResponse { data: OrderListItem[]; cursor?: Pagination }
interface OrderDetailResponse { order: Order }
interface CheckoutThankYouData {
  thank_you_title?: string;
  messages?: string[];
  share_message?: string;
  short_share_message?: string;
}

Try it live

A customer's orders. Every order endpoint needs a signed-in customer, so for you it stays switched off.Try this: change the status and withItems controls and watch the query key: every params object is its own cache entry.
Storefront canvas · en · LTR
Runs in the browser…
Controls
with_itemsAdds each order’s items to the list.
What a theme writes
import { useQuery } from '@tanstack/react-query';
import { getAuthToken } from '@salla.sa/twilight-theme-engine/api/client';
import { order } from '@salla.sa/twilight-theme-engine/api/order';

export function RecentOrders() {
  const { data } = useQuery({
    ...order.queries.list(),
    enabled: Boolean(getAuthToken()), // guests get 400 token_not_provided
  });

  return (
    <ul>
      {data?.data.map((item) => (
        <li key={item.id}>
          #{item.reference_id} · {item.status.name}
        </li>
      ))}
    </ul>
  );
}

Example

app/components/account/PendingOrders.tsx
import { useQuery } from '@tanstack/react-query';
import { getAuthToken } from '@salla.sa/twilight-theme-engine/api/client';
import { order } from '@salla.sa/twilight-theme-engine/api/order';

export function PendingOrders() {
  const { data } = useQuery({
    ...order.queries.list({ status: 'pending' }),
    enabled: Boolean(getAuthToken()), // a guest would get HTTP 400
  });

  return (
    <ul className="pending-orders">
      {data?.data.map((item) => (
        <li key={item.id}>
          #{item.reference_id} · {item.status.name} · {item.amounts.total.amount}{' '}
          {item.amounts.total.currency}
        </li>
      ))}
    </ul>
  );
}

How it behaves

  • Endpoints: GET orders (with page, cursor, status, feedback_status and with_items=1 only when given), GET orders/{id}, GET orders/{id}/shipments, GET orders/{id}/ratings and GET checkout/thank-you/{id}.

  • Every order endpoint needs a customer token. For a guest GET orders answers HTTP 400 with token_not_provided (demo store).

  • list and queries.list pass an AbortSignal on; list returns data ?? [] and the cursor block as the API sent it, unlike product.list, which returns items and next.

  • The engine thank-you loader asks order.find and order.thankYou together with Promise.allSettled, because a guest checkout has no token for orders/{id} and the page must still render.

  • The item types come with the account route: import type { Order, OrderListItem } from '@salla.sa/twilight-theme-engine/routes/account'. OrderShipmentItem and OrderRatingItem are not exported; use Awaited<ReturnType<typeof order.shipments>>.

Gotchas

  • order.findOrThrow maps only 401 and 403 to the unauthorized flow. A guest gets HTTP 400 token_not_provided, which is rethrown as a raw HTTPError, so the page shows an error instead of asking the shopper to sign in. Check getAuthToken() first.

  • The method is find but its key segment is detail: invalidate with order.queries.find(id).queryKey, not a hand-written ['orders', 'find', id].

  • src/api/README.md shows order.find(id, locale), and docs route-pagination.md shows order.list(locale, { … }) returning items. No order function takes a locale, and list returns data and cursor.

Related

Source and docs