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

**Repozytorium GitHub:** [https://github.com/KlipFit/kleep-rn](https://github.com/KlipFit/kleep-rn)

Cienka nakładka WebView wokół `drawer.kleep.ai`. SDK udostępnia jeden komponent i dwie metody, odwzorowując interfejs iOS.

## Instalacja

***

Każde wydanie jest publikowane jako paczka npm na `cdn.kleep.ai`. Dostępne są dwa formaty URL:

**Najnowsza stabilna wersja** (aktualizuje się automatycznie przy każdym nowym stabilnym wydaniu — wersje przedpremierowe nigdy nie przesuwają tego wskaźnika):

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

**Przypnij konkretną wersję** (zalecane dla środowiska produkcyjnego — w pełni niezmienne):

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

Zastąp `v1.0.0` i `1.0.0` żądanym tagiem wydania. Dwa wymienione pakiety to zależności peer — SDK wymaga ich, ale pozwala kontrolować wersję.

Opublikowana paczka zawiera plik SHA-256 obok niej (`<tarball>.sha256` / `latest.tgz.sha256`), jeśli chcesz zweryfikować integralność przed instalacją.

### Expo

Obie zależności peer są wstępnie spakowane w Expo Go (SDK 54+). W trybie deweloperskim nie jest potrzebna żadna dodatkowa konfiguracja. W przypadku kompilacji produkcyjnych `expo prebuild` pobiera je automatycznie.

### Bare React Native

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

## Uprawnienia

***

Dla przepływu obuwniczego (skanowanie aparatem), dodaj do `ios/<App>/Info.plist`:

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

Oraz do `android/app/src/main/AndroidManifest.xml`:

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

## Konfiguracja jednorazowa przy uruchomieniu aplikacji

***

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

| Pole       | Wymagane | Opis                                                                                                                   |
| ---------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
| `publicId` | tak      | UUID identyfikujący Twojego sprzedawcę (dostarczony przez Kleep)                                                       |
| `language` | nie      | `'fr' \| 'en' \| 'de' \| 'it' \| 'es' \| 'nl' \| 'pt' \| 'ja' \| 'ko' \| 'pl' \| 'br' \| 'dk' \| 'fi' \| 'se' \| 'gb'` |

## Użycie

***

### Metoda 1: `Kleep.checkProduct`

Wywołaj tę metodę podczas montowania strony PDP. Wynik steruje przyciskiem CTA „Znajdź mój rozmiar" — czy go wyświetlić i jaki napis pokazać.

| parametr    | priorytet  | opis                                        |
| ----------- | ---------- | ------------------------------------------- |
| `productId` | *wymagany* | Identyfikator Twojego produktu u sprzedawcy |

**Zwraca**

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

**Schemat logiki**

| `recommendable` | `recommendedSize` | Co wyświetlić                                        |
| --------------- | ----------------- | ---------------------------------------------------- |
| `false`         | —                 | **Ukryj CTA** (produkt nie kwalifikuje się do Kleep) |
| `true`          | brak              | CTA: **"Trouver ma taille"**                         |
| `true`          | `"M"`             | CTA: **"Taille recommandée: M"**                     |

SDK przechowuje wynik w pamięci podręcznej przez 5 minut, z kluczem `(publicId, productId)` dla bramki i `(publicId, productId, mid)` dla zalecanego rozmiaru. Ponowne renderowanie strony PDP lub nawigacja wstecz nie generuje kosztów.

**Przykład implementacji**

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

### Metoda 2: `<KleepFindSizeView>`

Zamontuj ten komponent, aby otworzyć panel znajdowania rozmiaru w pełnoekranowym Modal+WebView. Wzorzec sterowanego komponentu: Ty zarządzasz stanem `visible`, SDK żąda zamknięcia przez `onDismiss`.

| właściwość     | priorytet    | opis                                                                                                                                                                            |
| -------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `visible`      | *wymagana*   | Steruje widocznością Modal                                                                                                                                                      |
| `productId`    | *wymagana*   | Taki sam jak w `checkProduct`                                                                                                                                                   |
| `onDismiss`    | *wymagana*   | Wywoływany gdy użytkownik zamyka panel (X / przeciągnięcie / wstecz). Aplikacja MUSI ustawić `visible` na `false`                                                               |
| `variantId`    | *opcjonalna* | Wstępnie wybiera wariant dla rekomendacji                                                                                                                                       |
| `customerId`   | *opcjonalna* | Identyfikator CRM do łączenia między sesjami                                                                                                                                    |
| `language`     | *opcjonalna* | Nadpisuje język ustawiony na poziomie SDK dla tego otwarcia                                                                                                                     |
| `countryCode`  | *opcjonalna* | np. `"FR"`, `"US"` — określa system jednostek i domyślne rozmiary biustonoszy                                                                                                   |
| `stocks`       | *opcjonalna* | `{ [variantId]: number \| boolean }` — panel wyświetla UI dla niedostępnych / częściowo dostępnych produktów                                                                    |
| `mock`         | *opcjonalna* | `true` → panel pomija rzeczywiste wywołania API rekomendacji (tylko dla QA)                                                                                                     |
| `forceState`   | *opcjonalna* | `'outOfRange' \| 'unavailable' \| 'error' \| 'qrcode'` — wyjście QA do bezpośredniego renderowania stanu końcowego                                                              |
| `warmRestore`  | *opcjonalna* | `{ mid, uid }` — wstępne załadowanie istniejącego pomiaru (pominięcie przepływu wprowadzającego). Przywracanie na tym samym urządzeniu jest już automatyczne przez AsyncStorage |
| `extraParams`  | *opcjonalna* | Surowy `Record<string, string>` dołączany do URL panelu (mechanizm obejścia)                                                                                                    |
| `onAddToCart`  | *opcjonalna* | `(event: { variantId, size? }) => void` — użytkownik nacisnął przycisk „Dodaj do koszyka" wewnątrz panelu. **Aplikacja dodaje wariant do koszyka**                              |
| `onSelectSize` | *opcjonalna* | `(event: { size }) => void` — użytkownik wybrał rozmiar na ekranie wyników. **Aplikacja powinna zsynchronizować swój selektor rozmiaru na stronie PDP**                         |
| `onMessage`    | *opcjonalna* | Hak debugowania — uruchamiany dla każdej przychodzącej wiadomości postMessage przetworzonej z panelu                                                                            |
| `style`        | *opcjonalna* | `StyleProp<ViewStyle>` — nadpisanie stylów kontenera                                                                                                                            |
| `webViewProps` | *opcjonalna* | Przekazywane do `react-native-webview` w celu zaawansowanej personalizacji                                                                                                      |

**Automatycznie obsługiwane przez SDK (nie musisz nic robić):**

* Łączy komunikaty `window.parent.postMessage` w stylu iframe panelu z mostem React Native
* Zapisuje `mid` / `uid` w AsyncStorage, gdy panel je przesyła
* Odpowiada na wiadomości `getMid` / `getUid` / `getSizes` postMessage z panelu
* Wywołuje `Kleep.checkProduct` przy otwarciu w celu rozwiązania przepływu (clothing / lingerie / footwear / children) — używa tej samej 5-minutowej pamięci podręcznej co Twoje wywołanie CTA, więc jest bezkosztowe, jeśli już wywołałeś `checkProduct`

### Metoda 3: `Kleep.track`

Analityka w trybie „fire-and-forget". Nigdy nie zgłasza błędu.

| parametr             | priorytet    | opis                                               |
| -------------------- | ------------ | -------------------------------------------------- |
| `eventName`          | *wymagany*   | Nazwa zdarzenia                                    |
| `options.customerId` | *opcjonalny* | Identyfikator CRM                                  |
| `options.parameters` | *opcjonalny* | `Record<string, unknown>` — dowolne dane zdarzenia |

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

Chcemy śledzić 3 zdarzenia:

| eventName               | Wyzwalacz                                |
| ----------------------- | ---------------------------------------- |
| `product_viewed`        | Po wyświetleniu strony produktu (PDP)    |
| `product_added_to_cart` | Po dodaniu produktu do koszyka           |
| `checkout_completed`    | Po potwierdzeniu zamówienia po płatności |

**Przykład `product_viewed`**

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

**Przykład `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" }
    }
  ]
}
```

**Przykład `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" }
    }
  ]
}
```

## Unieważnianie pamięci podręcznej

***

SDK utrzymuje dwie pamięci podręczne w pamięci RAM (każda z TTL 5 min):

* **Bramka produktu** — `(publicId, productId) → { recommendable, category, productFound }`
* **Zalecany rozmiar** — `(publicId, productId, mid) → size label`

Obie są unieważniane automatycznie. Jeśli potrzebujesz wymusić odświeżenie (wylogowanie użytkownika, zmiana sprzedawcy, ręczny przycisk odświeżania):

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