> ## 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.

# Mobil SDK - React Native

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

En tynd WebView-wrapper omkring `drawer.kleep.ai`. SDK'et eksponerer én komponent + to metoder, der spejler iOS-overfladen.

## Installation

***

Hver udgivelse udgives som en npm-tarball på `cdn.kleep.ai`. To URL-former er tilgængelige:

**Seneste stabile** (auto-opdateres med hver ny stabil udgivelse — pre-releases flytter aldrig denne pointer):

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

**Fastgør en specifik version** (anbefalet til produktion — fuldt uforanderlig):

```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
```

Erstat `v1.0.0` og `1.0.0` med det ønskede release-tag. De to listede pakker er peer-afhængigheder — SDK'et kræver dem, men lader dig styre versionen.

Den udgivne tarball inkluderer en SHA-256 ved siden af (`<tarball>.sha256` / `latest.tgz.sha256`), hvis du ønsker at verificere integritet inden installation.

### Expo

Begge peer-deps er forudbundlet i Expo Go (SDK 54+). Ingen ekstra opsætning nødvendig i dev. Til produktionsbuilds hentes de automatisk af `expo prebuild`.

### Bare React Native

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

## Tilladelser

***

Til fodtøjsflowet (kamerascan) skal du tilføje til `ios/<App>/Info.plist`:

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

Og til `android/app/src/main/AndroidManifest.xml`:

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

## Konfigurér én gang ved app-opstart

***

```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
});
```

| Felt       | Påkrævet | Beskrivelse                                                                                                            |
| ---------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
| `publicId` | ja       | UUID der identificerer din forhandler (leveret af Kleep)                                                               |
| `language` | nej      | `'fr' \| 'en' \| 'de' \| 'it' \| 'es' \| 'nl' \| 'pt' \| 'ja' \| 'ko' \| 'pl' \| 'br' \| 'dk' \| 'fi' \| 'se' \| 'gb'` |

## Brug

***

### Metode 1: `Kleep.checkProduct`

Kald dette ved PDP-montering. Resultatet styrer "Find min størrelse"-CTA'en — om den skal gengives, og hvilken etiket der skal vises.

| parameter   | prioritet  | beskrivelse                     |
| ----------- | ---------- | ------------------------------- |
| `productId` | *påkrævet* | Dit produkt-ID hos forhandleren |

**Returnerer**

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

**Logikskema**

| `recommendable` | `recommendedSize` | Hvad der gengives                                      |
| --------------- | ----------------- | ------------------------------------------------------ |
| `false`         | —                 | **Skjul CTA'en** (produkt ikke kvalificeret til Kleep) |
| `true`          | fraværende        | CTA: **"Trouver ma taille"**                           |
| `true`          | `"M"`             | CTA: **"Taille recommandée: M"**                       |

SDK'et cacher resultatet i 5 min i hukommelsen, nøglet på `(publicId, productId)` til porten og `(publicId, productId, mid)` til den anbefalede størrelse. Gengivelse af PDP'en eller navigation tilbage er gratis.

**Implementeringseksempel**

```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)}
      />
    </>
  );
}
```

### Metode 2: `<KleepFindSizeView>`

Montér denne komponent for at åbne størrelsesfinder-skuffen i en fuldskærms Modal+WebView. Kontrolleret-komponent-mønster: du ejer `visible`-tilstanden, SDK'et anmoder om luk via `onDismiss`.

| prop           | prioritet  | beskrivelse                                                                                                                                         |
| -------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `visible`      | *påkrævet* | Styrer Modal-synlighed                                                                                                                              |
| `productId`    | *påkrævet* | Samme som i `checkProduct`                                                                                                                          |
| `onDismiss`    | *påkrævet* | Udløses når brugeren lukker skuffen (X / swipe / tilbage). Vært SKAL skifte `visible` til `false`                                                   |
| `variantId`    | *valgfri*  | Forvalgt en variant til anbefalingen                                                                                                                |
| `customerId`   | *valgfri*  | CRM-identifikator til tværsessions-linking                                                                                                          |
| `language`     | *valgfri*  | Tilsidesætter SDK-niveau-sproget for denne åbning                                                                                                   |
| `countryCode`  | *valgfri*  | f.eks. `"FR"`, `"US"` — styrer enhedssystem + BH-størrelsesstandard                                                                                 |
| `stocks`       | *valgfri*  | `{ [variantId]: number \| boolean }` — skuffe gengiver ikke tilgængeligt / delvist lager UI                                                         |
| `mock`         | *valgfri*  | `true` → skuffe springer rigtige anbefalings-API-kald over (kun QA)                                                                                 |
| `forceState`   | *valgfri*  | `'outOfRange' \| 'unavailable' \| 'error' \| 'qrcode'` — QA-luge til at gengive en slutstatus direkte                                               |
| `warmRestore`  | *valgfri*  | `{ mid, uid }` — forudindlæs en eksisterende måling (spring introflowet over). Genoprettelse på samme enhed er allerede automatisk via AsyncStorage |
| `extraParams`  | *valgfri*  | Rå `Record<string, string>` tilføjet til skuffens URL (flugtluge)                                                                                   |
| `onAddToCart`  | *valgfri*  | `(event: { variantId, size? }) => void` — bruger trykkede på "Læg i kurv"-CTA'en i skuffen. **Vært lægger varianten i sin kurv**                    |
| `onSelectSize` | *valgfri*  | `(event: { size }) => void` — bruger valgte en størrelse på resultatskærmen. **Vært bør synkronisere sin PDP-størrelsesvælger**                     |
| `onMessage`    | *valgfri*  | Debug-hook — udløses for hver indkommende postMessage parset fra skuffen                                                                            |
| `style`        | *valgfri*  | `StyleProp<ViewStyle>` — containerstil-tilsidesættelse                                                                                              |
| `webViewProps` | *valgfri*  | Videresendt til `react-native-webview` til avanceret tilpasning                                                                                     |

**Auto-tilsluttet af SDK'et (du behøver ikke gøre noget):**

* Bygger bro over skuffens iframe-stil `window.parent.postMessage` til React Native-broen
* Vedvarer `mid` / `uid` til AsyncStorage, når skuffen skubber dem
* Reagerer på `getMid` / `getUid` / `getSizes` postMessages fra skuffen
* Kalder `Kleep.checkProduct` ved åbning for at løse flowet (tøj / lingeri / fodtøj / børn) — bruger den samme 5-min-cache som dit CTA-kald, så det er gratis, hvis du allerede har kaldt `checkProduct`

### Metode 3: `Kleep.track`

Brand-og-glem-analyse. Kaster aldrig fejl.

| parameter            | prioritet  | beskrivelse                                          |
| -------------------- | ---------- | ---------------------------------------------------- |
| `eventName`          | *påkrævet* | Navn på hændelsen                                    |
| `options.customerId` | *valgfri*  | CRM-identifikator                                    |
| `options.parameters` | *valgfri*  | `Record<string, unknown>` — vilkårlige hændelsesdata |

```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 },
});
```

Vi ønsker at spore 3 hændelser:

| eventName               | Trigger                            |
| ----------------------- | ---------------------------------- |
| `product_viewed`        | Når PDP vises                      |
| `product_added_to_cart` | Når produkt lægges i kurven        |
| `checkout_completed`    | Når ordre bekræftes efter betaling |

**`product_viewed`-eksempel**

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

**`product_added_to_cart`-eksempel**

```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" }
    }
  ]
}
```

**`checkout_completed`-eksempel**

```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-ugyldiggørelse

***

SDK'et holder to in-memory-caches (5 min TTL hver):

* **Produktport** — `(publicId, productId) → { recommendable, category, productFound }`
* **Anbefalet størrelse** — `(publicId, productId, mid) → størrelseslabel`

Begge ugyldiggøres automatisk. Hvis du har brug for at tvinge en opdatering (bruger logget ud, forhandler skiftet, manuel opdateringsknap):

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