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

# モバイル SDK - React Native

**Github リポジトリ:** [https://github.com/KlipFit/kleep-rn](https://github.com/KlipFit/kleep-rn)

`drawer.kleep.ai` を薄くラップした WebView です。SDK はコンポーネント 1 つとメソッド 2 つを公開しており、iOS のインターフェースを踏襲しています。

## インストール

***

各リリースは `cdn.kleep.ai` に npm の tarball として公開されています。2 種類の URL 形式が利用できます:

**最新安定版**（新しい安定版リリースのたびに自動更新 — プレリリースはこのポインターを更新しません）:

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

**特定バージョンを固定**（本番環境推奨 — 完全に不変）:

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

`v1.0.0` および `1.0.0` を希望するリリースタグに置き換えてください。上記 2 つのパッケージはピア依存関係です — SDK はこれらを必要としますが、バージョンはお客様が管理できます。

公開された tarball には、インストール前に整合性を確認したい場合のために SHA-256 ファイル（`<tarball>.sha256` / `latest.tgz.sha256`）が同梱されています。

### Expo

両方のピア依存関係は Expo Go（SDK 54 以降）に事前バンドルされています。開発時の追加設定は不要です。本番ビルドでは `expo prebuild` が自動的に処理します。

### Bare React Native

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

## 権限

***

フットウェアフロー（カメラスキャン）には、`ios/<App>/Info.plist` に以下を追加してください:

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

また `android/app/src/main/AndroidManifest.xml` には以下を追加してください:

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

## アプリ起動時に一度だけ設定する

***

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

| フィールド      | 必須  | 説明                                                                                                                     |
| ---------- | --- | ---------------------------------------------------------------------------------------------------------------------- |
| `publicId` | はい  | 小売業者を識別する UUID（Kleep から提供）                                                                                             |
| `language` | いいえ | `'fr' \| 'en' \| 'de' \| 'it' \| 'es' \| 'nl' \| 'pt' \| 'ja' \| 'ko' \| 'pl' \| 'br' \| 'dk' \| 'fi' \| 'se' \| 'gb'` |

## 使用方法

***

### メソッド 1: `Kleep.checkProduct`

PDP マウント時に呼び出します。結果は「サイズを探す」CTA の表示可否とラベル表示に使用します。

| パラメータ       | 優先度  | 説明            |
| ----------- | ---- | ------------- |
| `productId` | *必須* | 小売業者における商品 ID |

**戻り値**

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

**ロジック スキーマ**

| `recommendable` | `recommendedSize` | 表示内容                             |
| --------------- | ----------------- | -------------------------------- |
| `false`         | —                 | **CTA を非表示**（Kleep の対象外商品）       |
| `true`          | なし                | CTA: **"Trouver ma taille"**     |
| `true`          | `"M"`             | CTA: **"Taille recommandée: M"** |

SDK は結果を 5 分間メモリキャッシュします（ゲート用に `(publicId, productId)`、推奨サイズ用に `(publicId, productId, mid)` をキーとして使用）。PDP を再レンダリングしたり戻ったりしても余分なコストはかかりません。

**実装例**

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

### メソッド 2: `<KleepFindSizeView>`

このコンポーネントをマウントすると、サイズファインダードロワーがフルスクリーン Modal+WebView で開きます。制御コンポーネントパターン: `visible` の状態はホスト側が管理し、SDK は `onDismiss` を通じてクローズを要求します。

| プロップ           | 優先度  | 説明                                                                                            |
| -------------- | ---- | --------------------------------------------------------------------------------------------- |
| `visible`      | *必須* | Modal の表示を制御                                                                                  |
| `productId`    | *必須* | `checkProduct` と同じ値                                                                           |
| `onDismiss`    | *必須* | ユーザーがドロワーを閉じたとき（X / スワイプ / 戻る）に発火。ホストは `visible` を `false` にする必要があります                         |
| `variantId`    | *任意* | レコメンドのバリアントを事前選択                                                                              |
| `customerId`   | *任意* | セッション間リンク用の CRM 識別子                                                                           |
| `language`     | *任意* | このオープン時に SDK レベルの言語設定を上書き                                                                     |
| `countryCode`  | *任意* | 例: `"FR"`、`"US"` — 単位系とブラサイズのデフォルトを決定                                                         |
| `stocks`       | *任意* | `{ [variantId]: number \| boolean }` — ドロワーに在庫なし/部分在庫 UI を表示                                  |
| `mock`         | *任意* | `true` → ドロワーが実際のレコメンデーション API 呼び出しをスキップ（QA 専用）                                               |
| `forceState`   | *任意* | `'outOfRange' \| 'unavailable' \| 'error' \| 'qrcode'` — 終了状態を直接レンダリングする QA ハッチ               |
| `warmRestore`  | *任意* | `{ mid, uid }` — 既存の測定値をプリロード（イントロフローをスキップ）。同一デバイスの復元は AsyncStorage を通じて自動的に行われます             |
| `extraParams`  | *任意* | ドロワー URL に追加される生の `Record<string, string>`（エスケープハッチ）                                          |
| `onAddToCart`  | *任意* | `(event: { variantId, size? }) => void` — ユーザーがドロワー内の「カートに追加」CTA をタップ。**ホストがカートにバリアントを追加します** |
| `onSelectSize` | *任意* | `(event: { size }) => void` — ユーザーが結果画面でサイズを選択。**ホストは PDP のサイズピッカーを同期させる必要があります**             |
| `onMessage`    | *任意* | デバッグフック — ドロワーから受信した postMessage のパース毎に発火                                                     |
| `style`        | *任意* | `StyleProp<ViewStyle>` — コンテナスタイルの上書き                                                         |
| `webViewProps` | *任意* | 高度なカスタマイズのために `react-native-webview` に転送                                                      |

**SDK が自動的に処理します（何もする必要はありません）:**

* ドロワーの iframe スタイル `window.parent.postMessage` を React Native ブリッジにブリッジ
* ドロワーが `mid` / `uid` をプッシュしたとき AsyncStorage に保存
* ドロワーからの `getMid` / `getUid` / `getSizes` postMessage に応答
* オープン時に `Kleep.checkProduct` を呼び出してフロー（衣料品 / ランジェリー / フットウェア / 子供向け）を解決 — CTA 呼び出しと同じ 5 分キャッシュを使用するため、すでに `checkProduct` を呼び出した場合はコストはかかりません

### メソッド 3: `Kleep.track`

ファイア・アンド・フォーゲットの分析。例外は投げません。

| パラメータ                | 優先度  | 説明                                     |
| -------------------- | ---- | -------------------------------------- |
| `eventName`          | *必須* | イベント名                                  |
| `options.customerId` | *任意* | CRM 識別子                                |
| `options.parameters` | *任意* | `Record<string, unknown>` — 任意のイベントデータ |

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

トラッキングしたい 3 つのイベント:

| eventName               | トリガー           |
| ----------------------- | -------------- |
| `product_viewed`        | PDP 閲覧時        |
| `product_added_to_cart` | 商品がカートに追加されたとき |
| `checkout_completed`    | 支払い後の注文確認時     |

**`product_viewed` の例**

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

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

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

## キャッシュの無効化

***

SDK は 2 つのインメモリキャッシュを保持します（それぞれ TTL 5 分）:

* **商品ゲート** — `(publicId, productId) → { recommendable, category, productFound }`
* **推奨サイズ** — `(publicId, productId, mid) → サイズラベル`

どちらも自動的に無効化されます。強制更新が必要な場合（ユーザーがログアウトした、小売業者が切り替わった、手動更新ボタンなど）:

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