Wishlist
The signed-in customer's saved products, starting from the ?page= in the address and loading further pages as they scroll.
import { Wishlist, WishlistPage, wishlistLoader, WishlistPageProps } from '@salla.sa/twilight-theme-engine/routes/account';In plain words
/account/wishlist lists the products the customer saved with the heart button, each with its price, an add-to-cart button and a remove button. More products load as they scroll.
Signature
const Wishlist: {
readonly id: 'customer.wishlist';
readonly loader: (
ctx: LoaderContext, // { search?: { page?: string | number }; locale?: string }
extend?: (data: WishlistPageProps, ctx: { params: {} }) => Record<string, unknown> | Promise<Record<string, unknown>>
) => Promise<WishlistPageProps>;
readonly head: (ctx: TwilightContext, data: WishlistPageProps) => HeadDescriptor;
readonly Component: React.LazyExoticComponent<(props: WishlistPageProps) => JSX.Element>;
};
const WishlistPage: typeof Wishlist.Component;
function wishlistLoader(ctx: LoaderContext): Promise<WishlistPageProps>;
interface WishlistPageProps {
page: Page; // { title, slug: 'wishlist' }
query: { page: number };
products: Product[];
pagination: RoutePagination; // only next is set
}Example
import { createFileRoute } from '@tanstack/react-router';
import { Wishlist } from '@salla.sa/twilight-theme-engine/routes/account';
import type { WishlistPageProps } from '@salla.sa/twilight-theme-engine/routes/account';
import { CustomerPageSkeleton } from '@salla.sa/twilight-theme-engine/skeleton';
import { withHead } from '@salla.sa/twilight-theme-engine/tanstack';
export const Route = createFileRoute('/{-$locale}/account/wishlist')({
validateSearch: (search: Record<string, unknown>) => {
const page = Number(search.page) || 1;
return page > 1 ? { page } : {};
},
loaderDeps: ({ search }) => ({ page: search.page }),
loader: ({ deps, params }): Promise<WishlistPageProps> =>
Wishlist.loader({ search: { page: deps.page ?? 1 }, locale: params.locale }),
head: withHead(Wishlist),
pendingComponent: () => <CustomerPageSkeleton />,
component: WishlistComponent,
});
function WishlistComponent() {
const data: WishlistPageProps = Route.useLoaderData();
return <Wishlist.Component {...data} />;
}
How it behaves
wishlistLoaderreadsNumber(ctx.search?.page) || 1and wraps the API call inorUnauthorized: a 401 or 403 shows the 401 page, which is what a guest gets (the wishlist API answers a request without a customer token with 401).The generated route keeps
?page=in the address only above 1, so page 1 has a clean URL.WishlistPageloads the following pages in the browser as the customer scrolls, starting atquery.page + 1. Each card's remove button callsuseWishlist().remove(id). Slots:customer:wishlist.items.startandcustomer:wishlist.items.end.headsets the title and hreflang alternates only.
Gotchas
paginationholds onlynext.currentandpreviousexist onRoutePaginationand are shown filled in packages/theme-engine/docs/route-pagination.md, but no loader sets them.
Related
The shopper's wishlist, shared by every component on the page: check a product, and add, remove or toggle it through the Salla SDK.
Profile, SettingsThe signed-in customer's profile and account settings pages, built from Salla's ready-made web components and refused to guests.
WalletThe signed-in customer's wallet balance and transaction history, starting from the ?page= in the address and loading more as they scroll.
Source and docs
- Engine source:
packages/theme-engine/src/routes/account/wishlist/index.tsx