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

# Agregar automáticamente un regalo gratis en un umbral

> Un caso de uso del Cart SDK que agrega un regalo gratis cuando el total del carrito cruza un umbral, y lo elimina si el total cae por debajo.

Observa el total del carrito y mantén un regalo gratis sincronizado con él: agrega el regalo una vez que el comprador cruza un umbral de gasto, elimínalo si vuelve a caer por debajo.

<Note>
  Para una versión configurada por el comerciante con niveles, reglas por mercado y una barra de progreso, usa el bloque [Rewards](/es/aftersell/cart/rewards-block), sin código. Esto es para cuando tu regla es algo que el bloque no puede expresar.
</Note>

<div id="the-snippet">
  ## El snippet
</div>

Pega en **Cart settings → Custom script → Initialization**, y establece las dos 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">
  ## Cómo funciona
</div>

**`reconcileGift`** describe el estado en el que el carrito *debería* estar, y luego hace como máximo un cambio para llegar ahí:

* Califica y el regalo no está → [`addItem`](/es/aftersell/cart/sdk-actions#additemvariantid-quantity) lo agrega.
* No califica y el regalo está → [`removeItem`](/es/aftersell/cart/sdk-actions#removeitemkey) lo elimina, por la `key` de la línea.
* De lo contrario → no hace nada.

Se ejecuta tanto en [`cart_loaded`](/es/aftersell/cart/sdk-events#cart_loaded) (para que un carrito que ya califica al cargar la página reciba el regalo) como en [`cart_updated`](/es/aftersell/cart/sdk-events#cart_updated) (para que reaccione a cada cambio posterior). Como `cart_loaded` se reproduce para los suscriptores tardíos, esto funciona sin importar cuándo se ejecute tu script.

<Warning>
  **Las protecciones `!gift` / `gift` son lo que impide que esto entre en bucle.** Agregar el regalo dispara `cart_updated`, que ejecuta `reconcileGift` de nuevo, y la segunda pasada encuentra el regalo ya presente, así que no hace nada. Quita las protecciones y obtienes un bucle infinito. Consulta [las dos reglas](/es/aftersell/cart/sdk-events#the-two-rules).
</Warning>

Ten en cuenta que agregar el regalo **aumenta el total del carrito**, así que un umbral cercano al precio de un producto puede oscilar: agregar un regalo de \$0 es seguro, pero un regalo con precio podría empujar el carrito por encima del umbral por sí solo. Mantén el regalo gratis, o compara contra un total que lo excluya.

<div id="adapting-it">
  ## Adaptarlo
</div>

**Condicionar por cantidad de artículos en lugar de gasto:**

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

**Condicionar a que un producto específico esté en el carrito:**

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

**Solo en ciertos países.** Lee [`context`](/es/aftersell/cart/sdk-overview#context), que está disponible antes de que el carrito se cargue:

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

**Excluir el regalo del umbral** para que no pueda sostenerse a sí mismo:

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

**Marca el regalo para que se lea como un regalo.** Una [transformación de línea](/es/aftersell/cart/sdk-hooks#registerlinetransform) puede cambiar el título de una línea, el título de la variante, su estado oculto y sus propiedades internas. Así que reetiquétala:

```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>
  Una transformación de línea **no puede ocultar los controles de cantidad de una línea**: sus únicos setters son `setTitle`, `setVariantTitle`, `setHidden` y `setInternalProperties`. Si un comprador cambia la cantidad del regalo, corrígela desde un handler de `cart_updated` en su lugar.
</Note>

<div id="where-to-go-next">
  ## Adónde ir después
</div>

* **[Bloque Rewards](/es/aftersell/cart/rewards-block)**: la versión sin código, con niveles.
* **[Acciones](/es/aftersell/cart/sdk-actions)**: `addItem`, `removeItem` y el resto.
* **[Eventos](/es/aftersell/cart/sdk-events)**: por qué importan las protecciones.
