npm package: @okatech/idn-react
Description: IDN React SDK — hooks and components for IDN identity
Latest version: 0.1.0

# @idn/react — SDK Identité Numérique du Gabon

Intégrez l'authentification IDN dans votre application React en quelques lignes. Le SDK offre deux approches :

1. **Composants embarqués** — Formulaires de connexion/inscription directement dans votre app
2. **Bouton de redirection** — Redirect OAuth classique vers le portail IDN

---

## Installation

```bash
npm install @idn/react
# ou
pnpm add @idn/react
```

## Pré-requis

Enregistrez votre application sur le [portail IDN](https://idn.ga/admin/applications) pour obtenir un **Client ID**. Ajoutez vos URLs de redirection (dev + prod).

---

## Démarrage rapide

### 1. Envelopper votre application avec `<IDNProvider>`

```tsx
// main.tsx
import { IDNProvider } from '@idn/react'

function App() {
  return (
    <IDNProvider
      clientId="votre-client-id"
      redirectUri="https://consulat.ga/auth/callback"
      issuer="https://idn.ga"  {/* optionnel, c'est la valeur par défaut */}
    >
      <VotreApplication />
    </IDNProvider>
  )
}
```

### 2. Ajouter les formulaires d'authentification

#### Formulaire de connexion

```tsx
import { IDNSignInForm } from "@idn/react";

function PageConnexion() {
  return (
    <IDNSignInForm
      onSuccess={(session) => {
        console.log("Connecté !", session.user.name);
        // Rediriger vers le tableau de bord, etc.
      }}
      onError={(error) => {
        console.error(error.code, error.message);
      }}
      onSwitchToSignUp={() => {
        // Naviguer vers la page d'inscription
      }}
    />
  );
}
```

#### Formulaire d'inscription

```tsx
import { IDNSignUpForm } from "@idn/react";

function PageInscription() {
  return (
    <IDNSignUpForm
      onSuccess={(session) => {
        console.log("Compte créé !", session.user.name);
      }}
      onError={(error) => {
        console.error(error.code, error.message);
      }}
      onSwitchToSignIn={() => {
        // Naviguer vers la page de connexion
      }}
    />
  );
}
```

#### Toggle connexion / inscription

```tsx
import { useState } from "react";
import { IDNProvider, IDNSignInForm, IDNSignUpForm } from "@idn/react";

function AuthPage() {
  const [mode, setMode] = useState<"signin" | "signup">("signin");

  return (
    <IDNProvider clientId="votre-client-id" redirectUri="/auth/callback">
      {mode === "signin" ?
        <IDNSignInForm
          onSuccess={(session) => (window.location.href = "/dashboard")}
          onSwitchToSignUp={() => setMode("signup")}
        />
      : <IDNSignUpForm
          onSuccess={(session) => (window.location.href = "/dashboard")}
          onSwitchToSignIn={() => setMode("signin")}
        />
      }
    </IDNProvider>
  );
}
```

---

## Personnalisation

### Thème via CSS Variables

Les formulaires utilisent des CSS custom properties pour le theming. Ajoutez-les dans votre CSS :

```css
/* Thème clair (défaut) */
:root {
  --idn-primary: #009639;
  --idn-primary-text: #ffffff;
  --idn-bg: #ffffff;
  --idn-text: #1a1a1a;
  --idn-muted: #6b7280;
  --idn-border: #e5e7eb;
  --idn-error: #dc2626;
  --idn-radius: 8px;
  --idn-font: Inter, system-ui, sans-serif;
}

/* Thème sombre */
.dark {
  --idn-primary: #00b348;
  --idn-primary-text: #ffffff;
  --idn-bg: #1a1a2e;
  --idn-text: #e5e7eb;
  --idn-muted: #9ca3af;
  --idn-border: #374151;
  --idn-error: #ef4444;
}
```

### Labels personnalisés (i18n)

Remplacez les labels par défaut (français) :

```tsx
<IDNSignInForm
  labels={{
    title: "Login",
    subtitle: "Sign in to your IDN account",
    email: "Email address",
    password: "Password",
    submit: "Sign in",
    submitting: "Signing in…",
    noAccount: "Don't have an account?",
    signUpLink: "Create one",
    invalidCredentials: "Invalid email or password.",
    errorGeneric: "Login failed.",
  }}
/>

<IDNSignUpForm
  labels={{
    title: "Create an IDN account",
    subtitle: "Your Gabonese digital identity",
    firstName: "First name",
    lastName: "Last name",
    email: "Email",
    password: "Password",
    submit: "Create my account",
    submitting: "Creating…",
    hasAccount: "Already have an account?",
    signInLink: "Sign in",
  }}
/>
```

### Masquer la bande du drapeau

```tsx
<IDNSignInForm showStripe={false} />
```

### Style inline ou className

```tsx
<IDNSignInForm
  className="ma-classe-perso"
  style={{ maxWidth: "360px", margin: "0 auto" }}
/>
```

---

## Hooks

Accédez à l'état d'authentification depuis n'importe quel composant enfant :

```tsx
import { useIDN, useUser, useSession } from "@idn/react";

function MonComposant() {
  // État global
  const { isAuthenticated, isLoading, signIn, signOut } = useIDN();

  // Profil utilisateur
  const { user } = useUser();

  // Session et token
  const { session, token } = useSession();

  if (isLoading) return <p>Chargement…</p>;
  if (!isAuthenticated) return <button onClick={signIn}>Connexion</button>;

  return (
    <div>
      <p>Bonjour {user?.name} !</p>
      <button onClick={signOut}>Déconnexion</button>
    </div>
  );
}
```

## Composants utilitaires

```tsx
import { SignedIn, SignedOut, IDNLoading, IDNUserButton } from "@idn/react";

function Layout() {
  return (
    <nav>
      <IDNLoading>Chargement…</IDNLoading>

      <SignedOut>
        <IDNSignIn label="Connexion avec IDN" />
      </SignedOut>

      <SignedIn>
        <IDNUserButton showName />
      </SignedIn>
    </nav>
  );
}
```

---

## Profil utilisateur (IDNUser)

Les données retournées dans `session.user` :

| Champ            | Type      | Scope requis     |
| ---------------- | --------- | ---------------- |
| `sub`            | `string`  | `openid`         |
| `name`           | `string`  | `profile`        |
| `given_name`     | `string?` | `profile`        |
| `family_name`    | `string?` | `profile`        |
| `email`          | `string`  | `email`          |
| `email_verified` | `boolean` | `email`          |
| `picture`        | `string?` | `profile`        |
| `nationality`    | `string?` | `identite_pivot` |
| `birthdate`      | `string?` | `identite_pivot` |
| `gender`         | `string?` | `identite_pivot` |
| `birthplace`     | `string?` | `identite_pivot` |

---

## Codes d'erreur

| Code                        | Description                            |
| --------------------------- | -------------------------------------- |
| `USER_ALREADY_EXISTS`       | Un compte existe déjà avec cet email   |
| `INVALID_EMAIL_OR_PASSWORD` | Identifiants incorrects                |
| `EMAIL_NOT_VERIFIED`        | L'email n'a pas encore été vérifié     |
| `USER_NOT_FOUND`            | Aucun compte trouvé                    |
| `NETWORK_ERROR`             | Impossible de contacter le serveur IDN |

---

## Référence API

### `<IDNProvider>`

| Prop                    | Type       | Requis | Description                                        |
| ----------------------- | ---------- | ------ | -------------------------------------------------- |
| `clientId`              | `string`   | ✅     | Client ID de votre application                     |
| `redirectUri`           | `string`   | ✅     | URL de callback OAuth                              |
| `issuer`                | `string`   | —      | URL du serveur IDN (défaut: `https://idn.ga`)      |
| `scopes`                | `string[]` | —      | Scopes à demander (défaut: `openid profile email`) |
| `postLogoutRedirectUri` | `string`   | —      | URL après déconnexion                              |

### `<IDNSignInForm>`

| Prop               | Type                            | Description                       |
| ------------------ | ------------------------------- | --------------------------------- |
| `onSuccess`        | `(session: IDNSession) => void` | Appelé après connexion réussie    |
| `onError`          | `(error: IDNAuthError) => void` | Appelé en cas d'erreur            |
| `onSwitchToSignUp` | `() => void`                    | Affiche le lien "Créer un compte" |
| `labels`           | `IDNSignInFormLabels`           | Override des labels               |
| `showStripe`       | `boolean`                       | Bande drapeau (défaut: `true`)    |
| `className`        | `string`                        | Classe CSS                        |
| `style`            | `CSSProperties`                 | Style inline                      |

### `<IDNSignUpForm>`

| Prop               | Type                            | Description                      |
| ------------------ | ------------------------------- | -------------------------------- |
| `onSuccess`        | `(session: IDNSession) => void` | Appelé après inscription réussie |
| `onError`          | `(error: IDNAuthError) => void` | Appelé en cas d'erreur           |
| `onSwitchToSignIn` | `() => void`                    | Affiche le lien "Se connecter"   |
| `labels`           | `IDNSignUpFormLabels`           | Override des labels              |
| `showStripe`       | `boolean`                       | Bande drapeau (défaut: `true`)   |
| `className`        | `string`                        | Classe CSS                       |
| `style`            | `CSSProperties`                 | Style inline                     |

---

## Licence

MIT — Identité Numérique du Gabon