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

# Ajouter automatiquement un cadeau gratuit à un seuil

> Un cas d'usage du Cart SDK qui ajoute un cadeau gratuit lorsque le total du panier franchit un seuil, et le retire si le total redescend en dessous.

Surveillez le total du panier et gardez un cadeau gratuit synchronisé avec lui : ajoutez le cadeau dès que l'acheteur franchit un seuil de dépense, retirez-le s'il redescend en dessous.

<Note>
  Pour une version configurée par le marchand avec des paliers, des règles par marché et une barre de progression, utilisez le bloc [Rewards](/fr/aftersell/cart/rewards-block), sans code. Ceci est destiné aux cas où votre règle est quelque chose que le bloc ne peut pas exprimer.
</Note>

<div id="the-snippet">
  ## L'extrait
</div>

Collez dans **Cart settings → Custom script → Initialization**, et définissez les deux constantes :

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
const FREE_GIFT_VARIANT_ID = 1234567890; // the gift product's variant id
const THRESHOLD_CENTS = 5000;            // $50.00, since totals are in cents

function reconcileGift(state) {
  const gift = state.items.find((line) => line.variantId === FREE_GIFT_VARIANT_ID);
  const qualifies = state.totalPrice >= THRESHOLD_CENTS;

  if (qualifies && !gift) {
    window.aftersell.cart.actions.addItem(FREE_GIFT_VARIANT_ID, 1);
  } else if (!qualifies && gift) {
    window.aftersell.cart.actions.removeItem(gift.key);
  }
}

window.aftersell.cart.events.on('cart_loaded', reconcileGift);
window.aftersell.cart.events.on('cart_updated', reconcileGift);
```

<div id="how-it-works">
  ## Comment ça fonctionne
</div>

**`reconcileGift`** décrit l'état dans lequel le panier *devrait* être, puis effectue au plus une modification pour y parvenir :

* Éligible et le cadeau n'y est pas → [`addItem`](/fr/aftersell/cart/sdk-actions#additemvariantid-quantity) l'ajoute.
* Non éligible et le cadeau y est → [`removeItem`](/fr/aftersell/cart/sdk-actions#removeitemkey) le retire, via la `key` de la ligne.
* Sinon → ne rien faire.

Elle s'exécute à la fois sur [`cart_loaded`](/fr/aftersell/cart/sdk-events#cart_loaded) (afin qu'un panier déjà éligible au chargement de la page reçoive le cadeau) et sur [`cart_updated`](/fr/aftersell/cart/sdk-events#cart_updated) (afin qu'elle réagisse à chaque modification ultérieure). Comme `cart_loaded` est rejoué pour les abonnés tardifs, cela fonctionne quel que soit le moment où votre script s'exécute.

<Warning>
  **Les garde-fous `!gift` / `gift` sont ce qui empêche cette boucle.** Ajouter le cadeau déclenche `cart_updated`, qui exécute à nouveau `reconcileGift`, et le second passage trouve le cadeau déjà présent, donc il ne fait rien. Retirez les garde-fous et vous obtenez une boucle infinie. Consultez [les deux règles](/fr/aftersell/cart/sdk-events#the-two-rules).
</Warning>

Notez qu'ajouter le cadeau **augmente le total du panier**, donc un seuil proche du prix d'un produit peut osciller : ajouter un cadeau à \$0 est sûr, mais un cadeau avec un prix pourrait à lui seul pousser le panier au-dessus du seuil. Gardez le cadeau gratuit, ou comparez avec un total qui l'exclut.

<div id="adapting-it">
  ## L'adapter
</div>

**Conditionner sur le nombre d'articles au lieu de la dépense :**

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
const qualifies = state.itemCount >= 3;
```

**Conditionner sur la présence d'un produit spécifique dans le panier :**

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
const qualifies = state.items.some((line) => line.productId === TRIGGER_PRODUCT_ID);
```

**Seulement dans certains pays.** Lisez [`context`](/fr/aftersell/cart/sdk-overview#context), disponible avant le chargement du panier :

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
const ELIGIBLE = ['US', 'CA'];

// Only register the handlers for eligible countries.
if (ELIGIBLE.includes(window.aftersell.cart.context.customer_country)) {
  window.aftersell.cart.events.on('cart_loaded', reconcileGift);
  window.aftersell.cart.events.on('cart_updated', reconcileGift);
}
```

**Exclure le cadeau du seuil** pour qu'il ne puisse pas se maintenir lui-même :

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
const subtotalWithoutGift = state.items.reduce(
  (sum, line) => (line.variantId === FREE_GIFT_VARIANT_ID ? sum : sum + line.finalLinePrice),
  0
);
const qualifies = subtotalWithoutGift >= THRESHOLD_CENTS;
```

**Marquer le cadeau pour qu'il se lise comme un cadeau.** Une [transformation de ligne](/fr/aftersell/cart/sdk-hooks#registerlinetransform) peut changer le titre d'une ligne, le titre de sa variante, son état masqué et ses propriétés internes. Renommez-la donc :

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.hooks.registerLineTransform((line) => {
  if (line.variantId === FREE_GIFT_VARIANT_ID) {
    line.setTitle('Free gift 🎁');
  }
});
```

<Note>
  Une transformation de ligne **ne peut pas masquer les contrôles de quantité d'une ligne**. Ses seuls setters sont `setTitle`, `setVariantTitle`, `setHidden` et `setInternalProperties`. Si un acheteur change la quantité du cadeau, corrigez-la plutôt depuis un gestionnaire `cart_updated`.
</Note>

<div id="where-to-go-next">
  ## Pour aller plus loin
</div>

* **[Bloc Rewards](/fr/aftersell/cart/rewards-block)** : la version sans code, avec des paliers.
* **[Actions](/fr/aftersell/cart/sdk-actions)** : `addItem`, `removeItem` et le reste.
* **[Événements](/fr/aftersell/cart/sdk-events)** : pourquoi les garde-fous sont importants.
