> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kleep.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Mobile SDK - React Native

**Github Repository:** [https://github.com/KlipFit/kleep-rn](https://github.com/KlipFit/kleep-rn)

Een dunne WebView-wrapper rond `drawer.kleep.ai`. De SDK biedt één component + twee methoden, vergelijkbaar met het iOS-oppervlak.

## Installatie

***

Elke release wordt gepubliceerd als een npm-tarball op `cdn.kleep.ai`. Er zijn twee URL-vormen beschikbaar:

**Nieuwste stabiele versie** (automatisch bijgewerkt bij elke nieuwe stabiele release — pre-releases verschuiven deze aanwijzer nooit):

```bash theme={null}
npm install https://cdn.kleep.ai/react-native-sdk/latest.tgz \
  react-native-webview \
  @react-native-async-storage/async-storage
```

**Een specifieke versie vastzetten** (aanbevolen voor productie — volledig onveranderlijk):

```bash theme={null}
npm install https://cdn.kleep.ai/react-native-sdk/releases/v1.0.0/kleep-react-native-1.0.0.tgz \
  react-native-webview \
  @react-native-async-storage/async-storage
```

Vervang `v1.0.0` en `1.0.0` door de gewenste releasetag. De twee vermelde pakketten zijn peer-afhankelijkheden — de SDK vereist ze maar laat u de versie bepalen.

De gepubliceerde tarball bevat een bijbehorende SHA-256 (`<tarball>.sha256` / `latest.tgz.sha256`) als u de integriteit wilt verifiëren vóór installatie.

### Expo

Beide peer-afhankelijkheden zijn vooraf gebundeld in Expo Go (SDK 54+). Er is geen extra setup nodig tijdens ontwikkeling. Voor productie-builds worden ze automatisch opgehaald door `expo prebuild`.

### Bare React Native

```bash theme={null}
cd ios && pod install
```

## Rechten

***

Voeg voor de schoeiselstroom (camerascan) het volgende toe aan `ios/<App>/Info.plist`:

```xml theme={null}
<key>NSCameraUsageDescription</key>
<string>Used to scan your shoe size</string>
```

En aan `android/app/src/main/AndroidManifest.xml`:

```xml theme={null}
<uses-permission android:name="android.permission.CAMERA" />
```

## Eenmalig configureren bij het starten van de app

***

```tsx theme={null}
import { Kleep } from '@kleep/react-native';

Kleep.configure({
  publicId: 'YOUR_KLEEP_PUBLIC_ID',  // UUID provided by Kleep
  language: 'fr',                      // optional, default UI language
});
```

| Veld       | Verplicht | Beschrijving                                                                                                           |
| ---------- | --------- | ---------------------------------------------------------------------------------------------------------------------- |
| `publicId` | ja        | UUID ter identificatie van uw retailer (verstrekt door Kleep)                                                          |
| `language` | nee       | `'fr' \| 'en' \| 'de' \| 'it' \| 'es' \| 'nl' \| 'pt' \| 'ja' \| 'ko' \| 'pl' \| 'br' \| 'dk' \| 'fi' \| 'se' \| 'gb'` |

## Gebruik

***

### Methode 1: `Kleep.checkProduct`

Roep dit aan bij het koppelen van de PDP. Het resultaat bepaalt de "Vind mijn maat"-CTA — of deze wordt weergegeven en welk label wordt getoond.

| parameter   | prioriteit  | beschrijving                  |
| ----------- | ----------- | ----------------------------- |
| `productId` | *verplicht* | Uw product-ID bij de retailer |

**Geeft terug**

```ts theme={null}
{
  recommendable: boolean;
  productFound: boolean;
  category?: 'clothing' | 'lingerie' | 'footwear' | 'children';
  recommendedSize?: string;   // e.g. "M", "38"
}
```

**Logisch schema**

| `recommendable` | `recommendedSize` | Wat weergeven                                        |
| --------------- | ----------------- | ---------------------------------------------------- |
| `false`         | —                 | **CTA verbergen** (product niet geschikt voor Kleep) |
| `true`          | afwezig           | CTA: **"Trouver ma taille"**                         |
| `true`          | `"M"`             | CTA: **"Taille recommandée: M"**                     |

De SDK slaat het resultaat 5 minuten op in het geheugen, met als sleutel `(publicId, productId)` voor de gate en `(publicId, productId, mid)` voor de aanbevolen maat. Het opnieuw renderen van de PDP of terugnavigeren is gratis.

**Implementatievoorbeeld**

```tsx theme={null}
import { useEffect, useState } from 'react';
import { Pressable, Text } from 'react-native';
import { Kleep, KleepFindSizeView, type KleepCheckProductResult } from '@kleep/react-native';

function ProductPage({ product }) {
  const [check, setCheck] = useState<KleepCheckProductResult | null>(null);
  const [open, setOpen] = useState(false);

  useEffect(() => {
    Kleep.checkProduct({ productId: product.id }).then(setCheck);
  }, [product.id]);

  if (!check?.recommendable) return <ProductContent />;

  return (
    <>
      <ProductContent />
      <Pressable onPress={() => setOpen(true)}>
        <Text>
          {check.recommendedSize
            ? `Taille recommandée : ${check.recommendedSize}`
            : 'Trouver ma taille'}
        </Text>
      </Pressable>
      <KleepFindSizeView
        visible={open}
        productId={product.id}
        variantId={selectedVariant?.id}
        onAddToCart={(e) => cart.add(e.variantId)}
        onSelectSize={(e) => pdp.setSize(e.size)}
        onDismiss={() => setOpen(false)}
      />
    </>
  );
}
```

### Methode 2: `<KleepFindSizeView>`

Koppel dit component om de maatzoeker-drawer te openen in een volledig scherm Modal+WebView. Gecontroleerd componentpatroon: u beheert de `visible`-toestand, de SDK vraagt sluiting aan via `onDismiss`.

| prop           | prioriteit  | beschrijving                                                                                                                                                     |
| -------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `visible`      | *verplicht* | Beheert de zichtbaarheid van de Modal                                                                                                                            |
| `productId`    | *verplicht* | Hetzelfde als in `checkProduct`                                                                                                                                  |
| `onDismiss`    | *verplicht* | Wordt geactiveerd wanneer de gebruiker de drawer sluit (X / swipe / terug). De host MOET `visible` naar `false` omschakelen                                      |
| `variantId`    | *optioneel* | Selecteert vooraf een variant voor de aanbeveling                                                                                                                |
| `customerId`   | *optioneel* | CRM-identificator voor koppeling tussen sessies                                                                                                                  |
| `language`     | *optioneel* | Overschrijft de SDK-taalkeuze voor dit openen                                                                                                                    |
| `countryCode`  | *optioneel* | bijv. `"FR"`, `"US"` — bepaalt eenheidssysteem + standaard BH-maten                                                                                              |
| `stocks`       | *optioneel* | `{ [variantId]: number \| boolean }` — drawer toont niet-beschikbare / gedeeltelijke voorraad UI                                                                 |
| `mock`         | *optioneel* | `true` → drawer slaat echte aanbeveling-API-aanroepen over (alleen QA)                                                                                           |
| `forceState`   | *optioneel* | `'outOfRange' \| 'unavailable' \| 'error' \| 'qrcode'` — QA-ingang om direct een eindtoestand te renderen                                                        |
| `warmRestore`  | *optioneel* | `{ mid, uid }` — laad een bestaande meting vooraf (sla de introductie over). Herstel op hetzelfde apparaat is al automatisch via AsyncStorage                    |
| `extraParams`  | *optioneel* | Raw `Record<string, string>` toegevoegd aan de drawer-URL (ontsnappingsluik)                                                                                     |
| `onAddToCart`  | *optioneel* | `(event: { variantId, size? }) => void` — gebruiker tikte op de "Toevoegen aan winkelwagen" CTA in de drawer. **Host voegt de variant toe aan zijn winkelwagen** |
| `onSelectSize` | *optioneel* | `(event: { size }) => void` — gebruiker koos een maat op het Resultaatscherm. **Host moet zijn PDP-maatkiezer synchroniseren**                                   |
| `onMessage`    | *optioneel* | Debug-hook — wordt geactiveerd voor elke inkomende postMessage geparseerd vanuit de drawer                                                                       |
| `style`        | *optioneel* | `StyleProp<ViewStyle>` — containeropmaak overschrijven                                                                                                           |
| `webViewProps` | *optioneel* | Doorgestuurd naar `react-native-webview` voor geavanceerde aanpassing                                                                                            |

**Automatisch gekoppeld door de SDK (u hoeft niets te doen):**

* Koppelt de iframe-stijl `window.parent.postMessage` van de drawer aan de React Native bridge
* Slaat `mid` / `uid` op in AsyncStorage wanneer de drawer ze pusht
* Reageert op `getMid` / `getUid` / `getSizes` postMessages van de drawer
* Roept `Kleep.checkProduct` aan bij het openen om de stroom te bepalen (kleding / lingerie / schoeisel / kinderen) — gebruikt dezelfde 5-minuten-cache als uw CTA-aanroep, dus het is gratis als u al `checkProduct` hebt aangeroepen

### Methode 3: `Kleep.track`

Fire-and-forget-analyse. Gooit nooit een fout.

| parameter            | prioriteit  | beschrijving                                                 |
| -------------------- | ----------- | ------------------------------------------------------------ |
| `eventName`          | *verplicht* | Naam van de gebeurtenis                                      |
| `options.customerId` | *optioneel* | CRM-identificator                                            |
| `options.parameters` | *optioneel* | `Record<string, unknown>` — willekeurige gebeurtenisgegevens |

```tsx theme={null}
import { Kleep } from '@kleep/react-native';

await Kleep.track('product_viewed', {
  parameters: { productId: product.id },
});

await Kleep.track('product_added_to_cart', {
  customerId: user.id,
  parameters: {
    productId: product.id,
    variantId: selectedVariant.id,
    cart: cart.items,
  },
});

await Kleep.track('checkout_completed', {
  customerId: user.id,
  parameters: { orderId: order.id, cart: order.items },
});
```

We willen 3 gebeurtenissen bijhouden:

| eventName               | Trigger                                                 |
| ----------------------- | ------------------------------------------------------- |
| `product_viewed`        | Wanneer de PDP wordt bekeken                            |
| `product_added_to_cart` | Wanneer een product aan de winkelwagen wordt toegevoegd |
| `checkout_completed`    | Bij orderbevestiging na de betaling                     |

**Voorbeeld `product_viewed`**

```jsx theme={null}
{
  productId: "123ABC456"
}
```

**Voorbeeld `product_added_to_cart`**

```jsx theme={null}
{
  productId: "123ABC456",
  variantId: "123ABC456-00R",
  cart: [
    {
      productId: "123ABC456",
      variantId: "123ABC456-00R",
      sku: "XYZ",
      size: "S",
      quantity: 2,
      price: { amount: "50", currencyCode: "EUR" }
    }
  ]
}
```

**Voorbeeld `checkout_completed`**

```jsx theme={null}
{
  orderId: "000001",
  cart: [
    {
      lineItemId: "000001#1",
      productId: "123ABC456",
      variantId: "123ABC456-00R",
      sku: "XYZ",
      size: "S",
      quantity: 2,
      price: { amount: "50", currencyCode: "EUR" }
    }
  ]
}
```

## Cache-ongeldigmaking

***

De SDK houdt twee in-memory caches bij (elk 5 minuten TTL):

* **Productpoort** — `(publicId, productId) → { recommendable, category, productFound }`
* **Aanbevolen maat** — `(publicId, productId, mid) → size label`

Beide verlopen automatisch. Als u een geforceerde vernieuwing nodig hebt (gebruiker uitgelogd, retailer gewisseld, handmatige vernieuwknop):

```tsx theme={null}
Kleep.clearCheckProductCache();
```
