# Shared types (https://docs.salla.dev/twilight/react/data/shared-types)





Use this page when a field on the store, product or cart points to a smaller shape (an image, a category, a price object) and you need its fields.

All types import from `@salla.sa/twilight-theme-engine/types`, except where a section says otherwise:

```ts
import type { Money, Category, MenuItem } from '@salla.sa/twilight-theme-engine/types';
```

The examples marked "Public store API" are real answers from the public demo store.

## Money [#money]

Where it appears: product variants (`skus[].price`), `base_currency_price` on a product, and cart lines (`price`, `total` and more).

Example (public store API, a product's `base_currency_price`):

```json
{ "currency": "SAR", "amount": 3 }
```

{/* types: ../../../../../theme-engine/src/types/index.ts#Money */}

| Field        | Type     | Description                              |
| ------------ | -------- | ---------------------------------------- |
| `amount`     | `number` | The amount as a number.                  |
| `currency`   | `string` | Currency code.                           |
| `formatted?` | `string` | Ready-made text, when the API sends one. |

{/* /types */}

Many price fields are plain numbers instead: on a product, `price`, `regular_price` and `sale_price` are numbers (`199`), and `currency` is a separate field. Cart lines can be either. Turn both into a number first, then format it with [`useMoney`](https://docs.salla.dev/twilight/react/hooks/use-money):

```tsx
import type { Money } from '@salla.sa/twilight-theme-engine/types';
import { useMoney } from '@salla.sa/twilight-theme-engine/hooks/useMoney';

function Price({ value }: { value: number | Money }) {
  const { format } = useMoney();
  const amount = typeof value === 'number' ? value : value.amount;
  return <>{format(amount, { currency: typeof value === 'number' ? undefined : value.currency })}</>;
}
```

## Images [#images]

Where it appears: `Product.image` and `Product.images`.

Example (public store API):

```json
{ "url": "https://cdn.salla.sa/mQgZlG/c58e19d6-...-500x500.jpg", "alt": "Chair" }
```

{/* types: ../../../../../theme-engine/src/types/index.ts#ProductImage */}

| Field                | Type                           | Description                                                                    |
| -------------------- | ------------------------------ | ------------------------------------------------------------------------------ |
| `id?`                | `number`                       | Image id.                                                                      |
| `url?`               | `string`                       | Image URL.                                                                     |
| `alt?`               | `string`                       | Alt text; usually the product name.                                            |
| `video_url?`         | `string`                       | Video URL when the item is a video, otherwise null.                            |
| `video_type?`        | `"video" \| "youtube" \| null` | `youtube` for a YouTube link, `video` for an uploaded file, null for an image. |
| `type?`              | `"image" \| "video"`           | Media kind. The API also sends '3d-image' for a 3D main image.                 |
| `three_d_image_url?` | `string`                       | `.glb` 3D model URL, or "" when none.                                          |
| `main?`              | `boolean`                      | True for the main image.                                                       |
| `sort?`              | `number`                       | Position in the gallery.                                                       |

{/* /types */}

`images` can be `null` when a product has a single image: read `image` first, and use `images ?? []`. Images on categories, brands, cart lines and menu items are plain URL strings, not this object.

## Category [#category]

Where it appears: category lists and pages ([`category` API](https://docs.salla.dev/twilight/react/api/modules/category)), and on a product as a smaller `ProductCategory` (`name`, `url`, optional `id`, `icon`, `image`).

Example (public store API, `GET categories`):

<JsonExplorer data="categoryExample" title="Category" defaultOpen="2" />

{/* types: ../../../../../theme-engine/src/types/index.ts#Category */}

| Field             | Type                 | Description                                                                                                                  |
| ----------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `id`              | `string \| number`   | Id as the API sends it, a hashed string such as "xzjvNQ".                                                                    |
| `id_?`            | `number`             | The raw numeric id, e.g. 868669273.                                                                                          |
| `name`            | `string`             | Category name.                                                                                                               |
| `description?`    | `string`             | Category description.                                                                                                        |
| `url`             | `string`             | Full URL of the category page.                                                                                               |
| `icon?`           | `string \| null`     | CSS icon class, e.g. "sicon-store", or null.                                                                                 |
| `image?`          | `string \| null`     | Flat image URL string (NOT a nested ProductImage object), or null. Aligns with both the API response and Twig.               |
| `products_count?` | `number`             | Number of products in the category.                                                                                          |
| `sub_categories?` | `Category[]`         | Child categories, possibly empty.                                                                                            |
| `items?`          | `Category[] \| null` | Mirror of `sub_categories` on parent categories (an array, possibly empty); `null` on some root categories without children. |

{/* /types */}

## Brand [#brand]

Where it appears: the brands list, brand pages and the home brands block. The engine has two `Brand` types:

* `Brand` from `@salla.sa/twilight-theme-engine/types`: `id: number`, `name`, `logo`, `url`. This is the small card shape.
* `Brand` from `@salla.sa/twilight-theme-engine/routes`: the full record used by the [brands pages](https://docs.salla.dev/twilight/react/routes/brands) and the [`brand` API](https://docs.salla.dev/twilight/react/api/modules/brands).

Example (public store API, `GET brands`, description shortened):

<JsonExplorer data="brandExample" title="Brand" defaultOpen="2" />

{/* types: ../../../../../theme-engine/src/routes/brands/types.ts#Brand */}

| Field         | Type                                                   | Description                                                                                |
| ------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------ |
| `id`          | `string \| number`                                     | Brand id. Numeric on the Store API (`brands` and `brands/{id}`); string in older fixtures. |
| `url`         | `string`                                               | Brand page URL.                                                                            |
| `name`        | `string`                                               | Brand name.                                                                                |
| `label`       | `string`                                               | Display label.                                                                             |
| `description` | `string`                                               | Brand description.                                                                         |
| `banner?`     | `string \| null`                                       | Banner image URL, or null.                                                                 |
| `logo`        | `string`                                               | Logo image URL. Always present; required to match Twig template usage.                     |
| `status`      | `boolean`                                              | Whether the brand is active.                                                               |
| `ar_char`     | `string`                                               | First Arabic letter, used to group the brands directory.                                   |
| `en_char`     | `string`                                               | First Latin letter, used to group the brands directory.                                    |
| `channels?`   | `string[]`                                             | Sales channels the brand is available on.                                                  |
| `metadata?`   | `{ title: string; description: string; url: string; }` | SEO data.                                                                                  |

#### `metadata` [#metadata]

| Field         | Type     | Description      |
| ------------- | -------- | ---------------- |
| `title`       | `string` | SEO title.       |
| `description` | `string` | SEO description. |
| `url`         | `string` | SEO URL.         |

{/* /types */}

<Callout type="warn">
  `id` is typed `string | number` and the API sends a number. Compare with `String(brand.id)`.
</Callout>

## MenuItem [#menuitem]

Where it appears: the header and footer menus ([`menu` API](https://docs.salla.dev/twilight/react/api/modules/menu)), usually passed to your header and footer components.

Example (public store API, `GET menus/header`, one item with one child):

<JsonExplorer data="menuItemExample" title="Menu item" defaultOpen="2" />

{/* types: ../../../../../theme-engine/src/types/index.ts#MenuItem */}

| Field           | Type               | Description                                                                            |
| --------------- | ------------------ | -------------------------------------------------------------------------------------- |
| `id`            | `string \| number` | Item id. Built-in links use a word, such as "offers" or "blog".                        |
| `title`         | `string`           | Text to show.                                                                          |
| `url`           | `string`           | Link URL.                                                                              |
| `image?`        | `string \| null`   | Root-level image the merchant attached in the menu builder, when there is one.         |
| `children?`     | `MenuItem[]`       | Sub-items. Missing on some items: use `children ?? []`.                                |
| `has_children?` | `boolean`          | Whether there are sub-items. Missing on some items.                                    |
| `target?`       | `string`           | Link target, e.g. "\_self".                                                            |
| `order?`        | `number`           | Sort position.                                                                         |
| `attrs?`        | `string`           | Raw HTML attribute string for the item element (e.g. ` id="offers"`).                  |
| `link_attrs?`   | `string`           | Raw HTML attribute string for the anchor (e.g. ` target="_self" class="offers-link"`). |

{/* /types */}

## Breadcrumb [#breadcrumb]

Where it appears: `useBreadcrumbs(page)` returns a list of them for the trail above a page.

Example (illustrative values):

```json
[
  { "name": "Home", "url": "/" },
  { "name": "Accessories", "url": "/accessories/c1309167683" }
]
```

{/* types: ../../../../../theme-engine/src/types/index.ts#Breadcrumb */}

| Field  | Type     | Description  |
| ------ | -------- | ------------ |
| `name` | `string` | Label.       |
| `url`  | `string` | Link target. |

{/* /types */}

```tsx
import { useBreadcrumbs } from '@salla.sa/twilight-theme-engine/hooks';

const crumbs = useBreadcrumbs(page); // [] on the home page
```

If the page has no trail of its own, the hook returns `Home` plus the page title. On a product page it inserts the list the customer came from.

## Page [#page]

Where it appears: every route loader returns a `page` object, which components pass to `useBreadcrumbs` and use for the title.

Example (illustrative values):

```json
{ "slug": "product.single", "title": "Chair", "id": 677709975, "url": "/chair/p677709975" }
```

{/* types: ../../../../../theme-engine/src/types/index.ts#Page */}

| Field          | Type                                                           | Description                                                                                 |
| -------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| `title`        | `string`                                                       | Page title.                                                                                 |
| `slug`         | `string`                                                       | Route id of the page, such as "product.single".                                             |
| `description?` | `string`                                                       | Page description.                                                                           |
| `id?`          | `string \| number`                                             | Entity ID associated with the page (e.g. category ID on a category page).                   |
| `url?`         | `string`                                                       | URL of the current page.                                                                    |
| `parent?`      | `{ id: string \| number; name: string; url: string; } \| null` | Parent entity, if any.                                                                      |
| `breadcrumbs?` | `Breadcrumb[]`                                                 | Breadcrumb trail built by the route loader. If omitted, useBreadcrumbs provides a fallback. |

#### `parent` [#parent]

| Field  | Type               | Description         |
| ------ | ------------------ | ------------------- |
| `id`   | `string \| number` | Parent entity id.   |
| `name` | `string`           | Parent entity name. |
| `url`  | `string`           | Parent entity URL.  |

#### `breadcrumbs` [#breadcrumbs]

| Field  | Type     | Description  |
| ------ | -------- | ------------ |
| `name` | `string` | Label.       |
| `url`  | `string` | Link target. |

{/* /types */}

A merchant's [custom page](https://docs.salla.dev/twilight/react/routes/custom-page) is a `Page` plus `content` (HTML), `metadata` and `created_at`, called `StaticPage`. The [`page` API](https://docs.salla.dev/twilight/react/api/modules/page) returns the raw record, for example from the public store: `{ "id": 153787377, "name": "Our team", "content": "<p>...</p>", "type": "general" }`.

## Language [#language]

Where it appears: `useTwilight().settings.languages`, the list behind a language switcher.

Example (public store API, `languages.EN`, plus the `iso_code` the engine adds):

<JsonExplorer data="languageExample" title="Language" defaultOpen="2" />

{/* types: ../../../../../theme-engine/src/types/index.ts#Language */}

| Field                      | Type      | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| -------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`                     | `string`  | Language name written in that language.                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `code`                     | `string`  | Language code.                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `iso_code?`                | `string`  | Same as `code` — the SDK's salla-localization-modal reads `iso_code`, not `code`.                                                                                                                                                                                                                                                                                                                                                                                                     |
| `url`                      | `string`  | Flag icon URL (e.g., "[https://assets.salla.sa/images/flags/ar.svg](https://assets.salla.sa/images/flags/ar.svg)") - NOT the store URL.                                                                                                                                                                                                                                                                                                                                               |
| `is_rtl`                   | `boolean` | Whether the language is written right to left.                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `country_code`             | `string`  | Country code used to pick the flag.                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `has_custom_translations?` | `boolean` | Whether this store has its own wording for this language. Written by `Languages-Module` when a merchant saves a translation, so a theme can tell without fetching whether `translations/<storeId>/<iso>.json` is worth asking for — most stores have none, and a miss is an uncached round trip on every render. Optional because it is new: a store nobody has written it for carries no key at all, and absent has to read as `false`. Do not treat a missing flag as "ask anyway". |

{/* /types */}

For the current language, use [`useTranslation()`](https://docs.salla.dev/twilight/react/hooks/use-translation) (`locale`, `direction`).

## Pagination [#pagination]

Where it appears: lists such as [`product.list`](https://docs.salla.dev/twilight/react/api/modules/product) return `PaginatedResult<T>` from `@salla.sa/twilight-theme-engine/api/types`.

```ts
interface PaginatedResult<T> {
  items: T[];
  next: string | null; // null on the last page
}
```

Example (illustrative values):

```json
{ "items": [ /* Product, Product, ... */ ], "next": "<opaque cursor>" }
```

{/* types: ../../../../../theme-engine/src/api/types.ts#PaginatedResult */}

| Field   | Type             | Description                                                                              |
| ------- | ---------------- | ---------------------------------------------------------------------------------------- |
| `items` | `T[]`            | The items of this page.                                                                  |
| `next`  | `string \| null` | Cursor for the next page, `null` on the last. Pass it back as `cursor`; do not parse it. |

{/* /types */}

The raw API also sends a cursor object (the `Pagination` type). Product list results keep it as `cursor` next to `items`; `cursor.current` is the page number for display only.

{/* types: ../../../../../theme-engine/src/api/types.ts#Pagination */}

| Field       | Type             | Description                                              |
| ----------- | ---------------- | -------------------------------------------------------- |
| `next?`     | `string \| null` | Cursor for the next page, or null on the last page.      |
| `previous?` | `string \| null` | Cursor for the previous page, or null on the first page. |
| `current`   | `number`         | Current page number, for UI display only.                |

{/* /types */}

```ts
const first = await product.list({ source: 'latest' });
const second = first.next ? await product.list({ source: 'latest', cursor: first.next }) : null;
```

## Testimonial and Slider [#testimonial-and-slider]

The types exist for theme code that renders store testimonials and home sliders. The engine declares them but does not load them from a named API module, so fill them from the data your own loader or the home block gives you.

### `Testimonial` [#testimonial]

{/* types: ../../../../../theme-engine/src/types/index.ts#Testimonial */}

| Field     | Type     | Description                        |
| --------- | -------- | ---------------------------------- |
| `id`      | `number` | Testimonial id.                    |
| `name`    | `string` | Name of the customer who wrote it. |
| `content` | `string` | Testimonial text.                  |
| `rating?` | `number` | Star rating the customer gave.     |
| `image?`  | `string` | Customer image URL.                |

{/* /types */}

### `Slider` [#slider]

{/* types: ../../../../../theme-engine/src/types/index.ts#Slider */}

| Field          | Type     | Description             |
| -------------- | -------- | ----------------------- |
| `id`           | `number` | Slide id.               |
| `image`        | `string` | Slide image URL.        |
| `link?`        | `string` | URL the slide links to. |
| `title?`       | `string` | Slide title.            |
| `description?` | `string` | Slide text.             |

{/* /types */}

## Next [#next]

* [Store data](https://docs.salla.dev/twilight/react/data/store), [Theme data](https://docs.salla.dev/twilight/react/data/theme) and [Product data](https://docs.salla.dev/twilight/react/data/product)
* [User data](https://docs.salla.dev/twilight/react/data/user) and [Cart data](https://docs.salla.dev/twilight/react/data/cart)
* [Data overview](https://docs.salla.dev/twilight/react/data)
