Loyalty
The loyalty program page, listing ways to earn points and prizes to redeem, or a 404 page when the store runs no program.
import { Loyalty, LoyaltyPage, loyaltyLoader, LoyaltyPageProps, LoyaltyPoint, LoyaltyPrize, LoyaltyPrizeItem } from '@salla.sa/twilight-theme-engine/routes/loyalty';In plain words
Some stores reward shoppers with points: for signing up, ordering, sharing the store. /loyalty explains the program, shows the shopper's balance and lists the prizes the points can buy. The page title is the program's own name.
Salla's demo store runs no loyalty program right now, so the page on Built-in pages shows the 404 page: exactly what your theme shows for such a store.
Signature
const Loyalty: {
readonly id: 'loyalty';
readonly loader: (
ctx?: { locale?: string },
extend?: (data: LoyaltyPageProps, ctx: { params: {} }) => Record<string, unknown> | Promise<Record<string, unknown>>
) => Promise<LoyaltyPageProps>;
readonly head: (ctx: TwilightContext, data: LoyaltyPageProps) => HeadDescriptor;
readonly Component: React.LazyExoticComponent<(props: LoyaltyPageProps) => JSX.Element>;
};
const LoyaltyPage: typeof Loyalty.Component;
function loyaltyLoader(): Promise<LoyaltyPageProps>;
interface LoyaltyPageProps {
page: Page; // title: the program name
loyalty: Loyalty; // the program: name, description, image, points, prizes… (type not exported)
}
interface LoyaltyPoint {
key: string; name: string; description: string; points: number; type: string;
icon: string; color: string; status: boolean; is_completed: boolean; conditions: LoyaltyCondition[]; …
}
interface LoyaltyPrize {
type: 'coupon_discount' | 'free_product' | 'free_shipping' | string;
title: string;
items: LoyaltyPrizeItem[];
}
interface LoyaltyPrizeItem {
id: number; name: string; cost_points: number;
description?: string; image?: string; url?: string; coupon_type?: string; coupon_amount?: number; …
}Example
import { createFileRoute } from '@tanstack/react-router';
import { Loyalty } from '@salla.sa/twilight-theme-engine/routes/loyalty';
import type { LoyaltyPageProps } from '@salla.sa/twilight-theme-engine/routes/loyalty';
import { withHead } from '@salla.sa/twilight-theme-engine/tanstack';
export const Route = createFileRoute('/{-$locale}/loyalty')({
loader: ({ params }): Promise<LoyaltyPageProps> => Loyalty.loader({ locale: params.locale }),
head: withHead(Loyalty),
component: LoyaltyComponent,
});
function LoyaltyComponent() {
const data: LoyaltyPageProps = Route.useLoaderData();
return <Loyalty.Component {...data} />;
}
How it behaves
loyaltyLoadercallsloyalty.getOrThrow(): when the store has no program, or the request fails, it throws the engine'sNotFoundErrorand the router's default error component shows a 404 page. (The demo store's API answers400with the message that the loyalty program is temporarily unavailable.)page.titleis the program'sname.headsets the title and hreflang alternates only.LoyaltyPagealso loads the signed-in customer's points in the browser (loyalty.queries.points()) and uses Salla's loyalty, button and slider web components. It renders no hook slots.Lazy: outside a route, wrap
LoyaltyPagein<Suspense>.
Gotchas
The program's data type is not exported, and its name
Loyaltybelongs to the route module. Type it asLoyaltyPageProps['loyalty'].
Related
Source and docs
- Engine source:
packages/theme-engine/src/routes/loyalty/index.tsx