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

# Bloki Custom code

> Blok Custom code w Aftersell Cart: dodawaj własny HTML lub React w dowolnym miejscu szuflady koszyka, także wewnątrz Cart items.

> Blok **Custom code** dodaje twój własny HTML lub React do koszyka. Umieść go w dowolnej sekcji szuflady albo zagnieźdź wewnątrz [**Cart items**](/pl/aftersell/cart/cart-items-block) jako sub-blok, aby powtarzał się dla każdej linii. W odróżnieniu od innych bloków nie ma ustawień Content ani sekcji Design: blok *jest* kodem, więc pracujesz wyłącznie w jego karcie **Code**.

<Frame>
  <img src="https://mintcdn.com/aftersell/1Y3gBpUfxv16VGSW/images/aftersell/cart-custom-code-block-add-and-enable.gif?s=6717cc64a8765b0c06b65990f99e12ff" alt="Animowany podgląd dodawania i włączania bloku Custom code w edytorze Aftersell Cart" title="Animowany podgląd dodawania i włączania bloku Custom code w edytorze Aftersell Cart" width="1200" height="558" data-path="images/aftersell/cart-custom-code-block-add-and-enable.gif" />
</Frame>

<div id="add-and-turn-on-a-custom-code-block">
  ## Dodaj i włącz blok Custom code
</div>

1. Dodaj blok **Custom code** do dowolnej sekcji albo jako sub-blok pod **Cart items**.
2. Zaznacz go i otwórz kartę **Code**.
3. Wybierz **HTML** lub **React component**. Nowe bloki domyślnie używają HTML.
4. Napisz swój kod.
5. Jeśli wybierzesz React, kliknij <span style={{display:'inline-flex',alignItems:'center',gap:'4px',background:'#1C1C1C',color:'#fff',border:'1px solid #0A0A0A',borderRadius:'4px',padding:'0 6px',fontSize:'0.85em',fontWeight:500,lineHeight:'1.4em',verticalAlign:'middle'}}><svg width="8" height="9" viewBox="0 0 10 12" fill="none" aria-hidden="true" style={{display:'block'}}><path d="M1.5 1.2v9.6L8.8 6 1.5 1.2Z" stroke="#fff" strokeWidth="1.5" strokeLinejoin="round" /></svg>Compile</span>.
6. Włącz **„Use custom template”**. Dla tego bloku ten przełącznik oznacza „pokaż mój niestandardowy kod” i domyślnie jest wyłączony, więc nic się nie renderuje, dopóki go nie włączysz.
7. Zostaw włączony przełącznik oka w pasku bocznym, aby blok pozostał widoczny dla kupujących.

Zarówno przełącznik oka, jak i **„Use custom template”** muszą być włączone, aby blok się pojawił.

<div id="behavior">
  ## Działanie
</div>

* Blok nie renderuje niczego, dopóki koszyk się nie załaduje.
* Nie renderuje też niczego, gdy oko w pasku bocznym jest wyłączone, **„Use custom template”** jest wyłączone, kod jest pusty albo React nie skompiluje się lub nie wyrenderuje. Ponieważ awaria jest cicha, sprawdź swój blok w [podglądzie](/pl/aftersell/cart/previewing-carts) przed publikacją.

<div id="html-mode">
  ## Tryb HTML
</div>

Tryb HTML podstawia mały zestaw tokenów do twojej struktury. Służy do treści statycznych lub opartych na tokenach, a nie do uruchamiania logiki.

* **Wbudowane tagi `<script>` nie działają**, a tryb HTML **nie ma dostępu do SDK ani `window`.**
* Dla logiki użyj [**trybu React**](#react-mode) lub [Niestandardowych skryptów](/pl/aftersell/cart/custom-scripts) z [Cart SDK](/pl/aftersell/cart/sdk-overview).

<div id="tokens">
  ### Tokeny
</div>

Wartości tokenów to **sformatowane ciągi znaków** (format walutowy sklepu, procent ze znakiem `%` lub ilość), gotowe do wstawienia w strukturę:

| Token                    | Co pokazuje                                                    |
| ------------------------ | -------------------------------------------------------------- |
| `{{pre_cart_total}}`     | Suma koszyka przed rabatami.                                   |
| `{{post_cart_total}}`    | Suma koszyka po rabatach.                                      |
| `{{savings_amount}}`     | Kwota oszczędności (suma przed rabatem minus suma po rabacie). |
| `{{savings_percentage}}` | Oszczędności jako procent, ze znakiem `%` (na przykład `15%`). |
| `{{cart_quantity}}`      | Liczba widocznych pozycji w koszyku.                           |

<div id="example">
  ### Przykład
</div>

```html theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
<div class="cart-external-custom-code_html">
  You saved {{savings_amount}} ({{savings_percentage}})
</div>
```

<div id="react-mode">
  ## Tryb React
</div>

Tryb React kompiluje komponent i przekazuje mu dane koszyka oraz akcję `add-to-cart`.

* Edytor blokuje wrapper na `function CustomCode(props: CustomCodeProps) { … }`, a ty edytujesz tylko treść między tymi liniami.
* Musisz kliknąć <span style={{display:'inline-flex',alignItems:'center',gap:'4px',background:'#1C1C1C',color:'#fff',border:'1px solid #0A0A0A',borderRadius:'4px',padding:'0 6px',fontSize:'0.85em',fontWeight:500,lineHeight:'1.4em',verticalAlign:'middle'}}><svg width="8" height="9" viewBox="0 0 10 12" fill="none" aria-hidden="true" style={{display:'block'}}><path d="M1.5 1.2v9.6L8.8 6 1.5 1.2Z" stroke="#fff" strokeWidth="1.5" strokeLinejoin="round" /></svg>Compile</span>, a następnie włączyć **„Use custom template”**, zanim blok się pokaże.
* Twój komponent może używać `useState`, `useEffect`, `useMemo`, `useRef` i `useCallback`.
* W odróżnieniu od trybu HTML, React działa w kontekście strony, więc może wywoływać `window` i [Cart SDK](/pl/aftersell/cart/sdk-overview), gdy są dostępne.
* Jeśli twój komponent rzuca błędy w czasie działania, blok nie renderuje niczego, a reszta koszyka działa dalej.

<div id="props">
  ### Propsy
</div>

Sumy i kwoty oszczędności to liczby całkowite w [jednostce podrzędnej](/pl/aftersell/cart/sdk-actions#formatmoneycents) waluty (centy dla USD), więc `$12.50` to `1250`, nie `12.50`. Nie są to sformatowane ciągi walutowe jak tokeny HTML.

| Prop                                            | Typ                         | Opis                                                                                                                            |
| ----------------------------------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `cart`                                          | `AftersellCart`             | Bieżący koszyk. Zobacz [dokumentację obiektu koszyka](/pl/aftersell/cart/sdk-cart-object).                                      |
| `line`                                          | `AftersellCartLine \| null` | Ustawiony tylko wtedy, gdy blok jest sub-blokiem Cart items (jedno renderowanie per linia); `null` w sekcji.                    |
| `preCartTotal`                                  | `number`                    | Suma koszyka **przed rabatami** (`original_total_price` Shopify), w jednostce podrzędnej waluty (np. centy).                    |
| `postCartTotal`                                 | `number`                    | Suma koszyka **po rabatach**, w jednostce podrzędnej waluty.                                                                    |
| `savings`                                       | `{ amount, percentage }`    | Kwota i procent oszczędności.                                                                                                   |
| `addProduct(variantId, quantity?, properties?)` | `function`                  | Dodaje produkt do koszyka, oznaczony atrybucją tego bloku, aby [analityka](/pl/aftersell/cart/analytics) mogła mu to przypisać. |

<div id="the-cart-and-line-shapes">
  ### Struktury cart i line
</div>

`cart` i `line` to te same obiekty, które SDK udostępnia wszędzie indziej, więc są udokumentowane raz w **[dokumentacji obiektu koszyka](/pl/aftersell/cart/sdk-cart-object)**: każde pole koszyka, linii i pakietu.

Te, po które będziesz sięgać najczęściej: `cart.items`, `cart.itemCount`, `cart.totalPrice`, `line.title`, `line.quantity`, `line.finalLinePrice`.

Trzy rzeczy specyficzne dla tego bloku:

* **`line` jest ustawiony tylko na sub-bloku Cart items**, gdzie twój komponent renderuje się raz per linia. Umieszczony jako sekcja, `line` jest `null` i zamiast tego czytasz `cart.items`.
* **Elementy podrzędne pakietu nie są w `cart.items`.** Gdy linie są [zgrupowane w pakiet](/pl/aftersell/cart/sdk-use-case-bundles), pojawia się tylko linia kotwicy; jej elementy podrzędne znajdują się w `line.bundle.children`.
* **Linii ukrytych przez [transformację linii](/pl/aftersell/cart/sdk-hooks#registerlinetransform) też tam nie ma**, choć nadal liczą się do `cart.totalPrice`.

<div id="examples">
  ### Przykłady
</div>

Pokaż liczbę pozycji:

```jsx theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
function CustomCode(props) {
  return (
    <div className="cart-external-custom-code_jsx">
      {props.cart.itemCount} items
    </div>
  );
}
```

Jako sub-blok Cart items użyj `props.line` do treści per produkt. Blok renderuje się raz per linia, oznaczony produktem i wariantem tej linii:

```jsx theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
function CustomCode(props) {
  if (!props.line) return null;
  return (
    <div className="cart-external-custom-code_jsx">
      {props.line.productTitle}
      {props.line.variantTitle ? ` · ${props.line.variantTitle}` : ''}
    </div>
  );
}
```

<div id="reading-enrichment-metadata">
  ### Odczytywanie metadanych wzbogacania
</div>

Każda pozycja w `cart.items` ma pole `metadata`: pusty obiekt `{}`, dopóki [cart enricher](/pl/aftersell/cart/sdk-hooks#registercartenricher) go nie wypełni. Po wypełnieniu jest kluczowane po `id` enrichera i zawiera dane Storefront dla produktu lub wariantu tej linii:

```jsx theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
function CustomCode(props) {
  return (
    <ul>
      {(props.cart.items ?? []).map((item) => {
        const note = item.metadata?.shipping?.shippingNote;
        return (
          <li key={item.key}>
            {item.title}
            {note ? ` · ${note.value}` : ''}
          </li>
        );
      })}
    </ul>
  );
}
```

`metadata` jest zawsze obecne i domyślnie jest pustym obiektem `{}`, dopóki asynchroniczne pobieranie enrichera się nie zakończy (test „jeszcze niewzbogacone” to `Object.keys(item.metadata).length === 0`). Używaj opcjonalnego łańcuchowania (`item.metadata?.enricherId`) przy odczycie klucza konkretnego enrichera, ponieważ ten klucz nie istnieje, dopóki wzbogacanie nie zostanie zakończone.

<div id="reading-discount-codes-and-line-discounts">
  ### Odczytywanie kodów rabatowych i rabatów linii
</div>

`cart.discountCodes` wymienia kody rabatowe zastosowane do koszyka, a `discountAllocations` każdej linii wymienia rabaty zastosowane do tej konkretnej linii:

```jsx theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
function CustomCode(props) {
  const codes = props.cart.discountCodes;
  return (
    <div>
      {codes.length > 0 && (
        <p>Active discounts: {codes.join(', ')}</p>
      )}
      <ul>
        {(props.cart.items ?? []).map((item) => {
          return (
            <li key={item.key}>
              {item.title}
              {item.discountAllocations.map(
                (discount) => ` · ${discount.title} (-${(discount.amount / 100).toFixed(2)})`
              )}
            </li>
          );
        })}
      </ul>
    </div>
  );
}
```

<div id="placement-and-limits">
  ## Umiejscowienie i limity
</div>

* **Region:** dowolny (góra, treść lub dół). Dostępny także jako sub-blok Cart items.
* **Maksimum:** bez limitu.
* **Stan:** wypełniony i pusty koszyk (jako blok sekcji). Jako sub-blok Cart items renderuje się tylko wtedy, gdy koszyk ma linie — jedna instancja per linia.
* Nie jest zablokowany, więc możesz go usunąć lub ukryć.
* Nie ma sekcji Design per blok. Stylizuj przez własną strukturę, [**Custom CSS**](/pl/aftersell/cart/custom-css) i globalne [**Ustawienia designu**](/pl/aftersell/cart/design-settings).

<div id="when-to-use-custom-code-block-vs-custom-template-vs-custom-script">
  ## Kiedy użyć bloku custom code, szablonu niestandardowego, a kiedy skryptu niestandardowego
</div>

|                                                                   | Co robi                                                                                 | Kiedy użyć                                                                         | Przykład                                                                                                                                                                 |
| ----------------------------------------------------------------- | --------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Blok Custom code**                                              | Dodaje *nowy* blok z twoim własnym HTML lub Reactem.                                    | Coś, czego nie pokrywają wbudowane bloki.                                          | Linia szacowanej sumy dodająca twoją stałą stawkę wysyłki do sumy koszyka albo odliczanie do granicy czasu dostawy nad przyciskiem checkoutu.                            |
| **[Szablon niestandardowy](/pl/aftersell/cart/custom-templates)** | Zastępuje renderowanie *istniejącego* bloku twoim JSX, korzystając z danych tego bloku. | Wbudowany blok jest prawie dobry, ale potrzebujesz innej struktury.                | Przebudowa [wiersza Product](/pl/aftersell/cart/cart-items-block#custom-template), aby nazwa wariantu, oszczędności i selektor ilości znalazły się w jednej linii.       |
| **[Skrypt niestandardowy](/pl/aftersell/cart/custom-scripts)**    | Uruchamia JavaScript na koszyku poprzez [Cart SDK](/pl/aftersell/cart/sdk-overview).    | Logika, zdarzenia i konfiguracja obejmujące cały koszyk, a nie struktura szuflady. | Wydaj \$75, odbierz darmową torbę: [dodaj prezent](/pl/aftersell/cart/sdk-use-case-free-gift), gdy koszyk przekroczy próg, i zabierz go, jeśli kupujący spadnie poniżej. |
