# Loyalty (https://docs.salla.dev/twilight/react/routes/loyalty)



<Callout title="Framework: TanStack Start">
  This page is written for TanStack Start, the default and currently supported framework. [See what depends on the framework](https://docs.salla.dev/twilight/react/start/frameworks).
</Callout>

The customer sees the store's points programme: a banner, the ways to earn points, the prizes points can buy, and a button to exchange points. Anyone can open it, and signed-in customers also see their balance. Customise it to retitle the page or wrap it in your own layout.

## URL [#url]

| Pattern               | Example                   |
| --------------------- | ------------------------- |
| `/{-$locale}/loyalty` | `/loyalty`, `/ar/loyalty` |

The only param is the optional `locale`. There are no search params.

## Route file [#route-file]

```tsx title="app/routes/loyalty.tsx"
// @auto-generated
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} />;
}
```

To take the page over, delete the `// @auto-generated` line and edit the file. See [Fork a built-in route](https://docs.salla.dev/twilight/react/recipes/fork-a-built-in-route).

### A customised version [#a-customised-version]

The loader's second argument, `extend`, returns extra fields that are merged into the data. Here it changes the page title:

```tsx title="app/routes/loyalty.tsx"
loader: ({ params }): Promise<LoyaltyPageProps> =>
  Loyalty.loader({ locale: params.locale }, (data) => ({
    page: { ...data.page, title: `${data.loyalty.name} - Rewards` },
  })),
```

### The points log [#the-points-log]

The Salla SDK's "view points log" link goes to `/loyalty_points`: a second route, `loyalty_points.tsx`, built from `LoyaltyPoints` in the same `routes/loyalty` module, with the same loader and `extend` argument. It shows the SDK's points history inside the customer layout and needs a signed-in customer.

## What it loads [#what-it-loads]

`LoyaltyPageProps` has `page` (`{ slug, title }`, where the title is the programme name) and `loyalty`: the programme's name, description, image, points rules and prizes. The loader fetches it on the server.

In the browser the page also fetches the customer's balance. That request is skipped when there is no token, so guests send nothing.

The head sets the title, description and language alternates.

## Edge cases [#edge-cases]

* **Programme switched off.** When the API answers 400 (the store has no loyalty programme), the loader redirects to the store home, with `ar` when the URL has no language. Any other failure shows the router's error page.
* **Guests.** The page renders without a balance line. The exchange button area is shown only to signed-in customers.

## See also [#see-also]

* [Testimonials](https://docs.salla.dev/twilight/react/routes/testimonials), the next page in More
* [Loading data](https://docs.salla.dev/twilight/react/guide/loading-data)
* [Making requests](https://docs.salla.dev/twilight/react/api#making-a-request)
