Orders
The signed-in customer's order history, optionally filtered by status, as a table that loads more orders on request.
import { Orders, OrdersPage, ordersLoader, OrdersPageProps, OrdersQuery, OrdersSearchParams } from '@salla.sa/twilight-theme-engine/routes/account/orders';In plain words
/account/orders lists the customer's orders: number, total, date and status, each row linking to that order. Adding ?status=pending to the address shows only pending orders and changes the page title.
Signature
const Orders: {
readonly id: 'customer.orders.index';
readonly loader: (
ctx: { search?: OrdersSearchParams; locale?: string; with_items?: boolean | number },
extend?: (data: OrdersPageProps, ctx: { params: {} }) => Record<string, unknown> | Promise<Record<string, unknown>>
) => Promise<OrdersPageProps>;
readonly head: (ctx: TwilightContext, data: OrdersPageProps) => HeadDescriptor;
readonly Component: React.LazyExoticComponent<(props: OrdersPageProps) => JSX.Element>;
};
const OrdersPage: typeof Orders.Component;
function ordersLoader(
ctx: { query?: OrdersQuery; with_items?: boolean | number }, // query, not search
extend?: (data: OrdersPageProps, ctx: { params: {} }) => Record<string, unknown> | Promise<Record<string, unknown>>
): Promise<OrdersPageProps>;
interface OrdersQuery { status?: string; feedback_status?: string }
type OrdersSearchParams = OrdersQuery;
interface OrdersPageProps {
page: Page;
orders: OrderListItem[];
cursor?: Pagination;
query?: OrdersQuery;
}Example
import { createFileRoute } from '@tanstack/react-router';
import { Orders } from '@salla.sa/twilight-theme-engine/routes/account/orders';
import type { OrdersPageProps } from '@salla.sa/twilight-theme-engine/routes/account/orders';
import { CustomerPageSkeleton } from '@salla.sa/twilight-theme-engine/skeleton';
import { withHead } from '@salla.sa/twilight-theme-engine/tanstack';
export const Route = createFileRoute('/{-$locale}/account/orders')({
validateSearch: (search: Record<string, unknown>) => {
const status = (search.status as string) || undefined;
return status ? { status } : {};
},
loaderDeps: ({ search }) => ({ status: search.status }),
loader: ({ deps, params }): Promise<OrdersPageProps> =>
Orders.loader({ search: { status: deps.status }, locale: params.locale }),
head: withHead(Orders),
pendingComponent: () => <CustomerPageSkeleton />,
component: OrdersComponent,
});
function OrdersComponent() {
const data: OrdersPageProps = Route.useLoaderData();
return <Orders.Component {...data} />;
}
How it behaves
ordersLoaderwraps the API call inorUnauthorized: a 401 or 403 shows the 401 page, any other error propagates. It sendsstatus,feedback_statusand, when set,with_items.OrdersPageshowsNoContentfor an empty list. Its load-more button passesstatusandfeedback_statusagain, but notwith_items.headtakes the title from the address, not the loader data:common.titles.pending_orderswhenlocation.search.statusispending,common.titles.ordersotherwise.OrdersPageignorespage(the account layout shows the title). It draws a table (ItemsListin button mode) whose load-more button fetches fromcursor.nextwith the samestatusandfeedback_status, between the slotscustomer:orders.index.items.startandcustomer:orders.index.items.end.The generated route forwards only
statusfrom the address;feedback_statusandwith_itemsare options for a route you write.Orders,OrdersPage,ordersLoaderand the props types are also re-exported from@salla.sa/twilight-theme-engine/routes/account.
Gotchas
A guest does not get the 401 page.
orUnauthorizedturns only a 401 or 403 into it, and Salla answers a request without a customer token with400 token_not_provided(checked on the demo store for orders, order details, notifications and the wallet), so the router's default error component shows a 400 page. The same holds forOrderSingle,NotificationsandWallet; the wishlist API does answer 401.Orders.loaderrunsextendtwice: it passes it toordersLoader, which merges the result, and then mergesextendagain (packages/theme-engine/src/routes/account/orders/index.tsx). Anextendthat fetches makes two requests.The raw loader's filter is
query, the module loader's issearch.ordersLoader({ search: { status: 'pending' } })filters nothing.docs/03-routing-system.md calls
Orders.loader({ locale: 'ar', status: 'pending' })and listshasMoreandstatusprops. Thatstatusis ignored (usesearch: { status }), and neither prop exists.
Related
One order's details for its customer: items, amounts, shipping and status, with reorder, cancel, receipt and rating actions.
Order, OrderItem, OrderListItemThe order shapes the account and thank-you pages use: a full order, one line of it, and the lighter row the orders list returns.
Profile, SettingsThe signed-in customer's profile and account settings pages, built from Salla's ready-made web components and refused to guests.
orThrow, orUnauthorizedWrap an API call in a loader: orThrow turns any failure into a not-found error, orUnauthorized turns a 401 or 403 into the unauthorized flow.
Source and docs
- Engine source:
packages/theme-engine/src/routes/account/orders/index.tsx