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

# Grupuj pozycje bundle z innej aplikacji

> Użyj setInternalProperties, aby powiedzieć koszykowi Aftersell Cart, które pozycje należą do tego samego bundla, tak by renderowały się jako jeden produkt zamiast kilku niepowiązanych pozycji.

Większość aplikacji bundle buduje bundle, dodając **każdy komponent jako osobną pozycję koszyka**, a następnie łącząc je własnymi właściwościami pozycji. Ajax API Shopify przekazuje te pozycje do koszyka bez żadnej informacji, że należą do siebie, więc domyślnie szuflada pokazuje trzyczęściowy bundle jako trzy niepowiązane produkty, każdy z własną ceną i przełącznikiem ilości.

`setInternalProperties` to sposób, aby powiedzieć koszykowi, że to jedna całość.

<div id="how-grouping-works">
  ## Jak działa grupowanie
</div>

Koszyk grupuje pozycje na podstawie dwóch **właściwości kanonicznych**. Nie zna nazw właściwości Twojej aplikacji bundle, więc tłumaczysz: odczytaj to, co zapisała aplikacja, i oznacz każdą pozycję kanoniczną parą za pomocą [transformacji pozycji](/pl/aftersell/cart/sdk-hooks#registerlinetransform).

| Właściwość                    | Wymagana | Wartość                                                              |
| ----------------------------- | -------- | -------------------------------------------------------------------- |
| `_aftersell_cart_bundle_id`   | Tak      | Wspólny identyfikator. Każda pozycja z tym samym ID to jeden bundle. |
| `_aftersell_cart_bundle_role` | Nie      | Ustaw `parent` na pozycji, jako która bundle ma się wyświetlać.      |

Przechodzą one przez `setInternalProperties`, nie przez Shopify. To **nakładka tylko do renderowania**: nigdy nie trafiają do `properties`, nigdy nie są zapisywane w Shopify i nigdy nie pojawiają się na zamówieniu.

<div id="step-1-find-out-what-your-app-writes">
  ## Krok 1: sprawdź, co zapisuje Twoja aplikacja
</div>

Każda aplikacja bundle nazywa swoje właściwości inaczej, więc zacznij od obejrzenia prawdziwego koszyka. Dodaj bundle w sklepie, a następnie uruchom to w konsoli przeglądarki:

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.actions.getCart().items.forEach((line) => {
  console.log(line.title, line.properties);
});
```

Szukasz właściwości wspólnej dla pozycji bundla. Zazwyczaj jest to ukryta właściwość (nazwa zaczyna się od `_`) zawierająca identyfikator, referencję lub nazwę bundla. Typowe są np. `_bundle_id`, `_bundle_ref` lub `_parent_id`. Zanotuj dokładny klucz oraz to, czy jedna pozycja jest oznaczona jako produkt główny.

<div id="step-2-map-it-onto-the-canonical-properties">
  ## Krok 2: zmapuj to na właściwości kanoniczne
</div>

Wklej w **Cart settings → Custom script → Initialization**, zastępując nazwy właściwości tymi, które znalazłeś:

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.hooks.registerLineTransform((line) => {
  const props = line.properties;
  if (!props) return;

  const bundleId = props._bundle_id;
  if (!bundleId) return;

  line.setInternalProperties({
    _aftersell_cart_bundle_id: bundleId,
    // Mark the main product so the bundle renders under it.
    _aftersell_cart_bundle_role: props._bundle_role === 'main' ? 'parent' : 'child',
  });
});
```

To cała integracja. Gdy tylko dwie lub więcej pozycji dzieli identyfikator, koszyk składa je w jeden bundle.

<Note>
  Jeśli Twoja aplikacja nie oznacza produktu głównego, pomiń całkowicie `_aftersell_cart_bundle_role`. Koszyk sam wybierze kotwicę.
</Note>

<div id="what-you-get">
  ## Co zyskujesz
</div>

Gdy pozycje są zgrupowane, pozycja-kotwica niesie [obiekt `bundle`](/pl/aftersell/cart/sdk-cart-object#bundles), a szuflada renderuje bundle jako jeden produkt:

* **Dzieci zagnieżdżają się pod kotwicą** zamiast pojawiać się jako osobne wiersze.
* **Ilość jest atomowa.** Zmiana ilości bundla skaluje wszystkich członków razem, używając proporcji `perAnchorQty` każdego dziecka, więc bundle z dwoma sztukami jednego komponentu zachowuje ten stosunek dwa do jednego.
* **Usuwanie jest atomowe.** Usunięcie bundla usuwa każdą pozycję członkowską w jednym żądaniu, zamiast zostawiać osierocone komponenty.
* **Jeden wiersz ceny.** To, co pokazuje, wynika z ustawienia **bundle price** w bloku [Cart items](/pl/aftersell/cart/cart-items-block): suma wszystkich członków albo sama cena produktu głównego.

<div id="how-the-anchor-is-chosen">
  ## Jak wybierana jest kotwica
</div>

Kotwica to pozycja, jako która bundle się wyświetla. Koszyk wybiera ją w tej kolejności:

1. Pozycja z `_aftersell_cart_bundle_role` ustawionym na `parent`.
2. W przeciwnym razie członek o **najwyższej cenie**.
3. W przeciwnym razie pierwszy członek w koszyku.

Rezerwa cenowa zwykle jest trafna, ponieważ aplikacje bundle zazwyczaj przypisują rabat do produktu głównego. Ustaw rolę jawnie, gdy tak nie jest, na przykład gdy produkt główny jest najtańszą pozycją albo jest darmowy.

<div id="rules-worth-knowing">
  ## Zasady warte poznania
</div>

* **Bundle potrzebuje co najmniej dwóch pozycji.** Pojedyncza pozycja z identyfikatorem bundla jest pozostawiana w spokoju i renderuje się normalnie.
* **Natywne bundle Shopify są już obsłużone.** Pozycje, które Shopify samo oznacza jako skomponowane, są pomijane przez to grupowanie i adaptowane automatycznie. Potrzebujesz tego tylko dla aplikacji dodających osobne pozycje.
* **Transformacja działa przy każdym renderze.** Utrzymuj ją lekką i bez efektów ubocznych. Nie wywołuj z jej wnętrza akcji ani nie wykonuj fetch.
* **Scalanie jest addytywne.** Twoje właściwości scalają się z tymi ustawionymi przez inną transformację. Przy rzeczywistym konflikcie o ten sam klucz wygrywa transformacja zarejestrowana jako ostatnia.
* **Grupowanie odbywa się po ukrywaniu i zmianie nazw**, a przed sortowaniem. Zatem pozycja ukryta przez `setHidden` nigdy nie staje się częścią bundla, a [komparator](/pl/aftersell/cart/sdk-hooks#registerlinecomparator) widzi kotwicę, nie dzieci.

<Warning>
  **Zgrupowane dzieci opuszczają `state.items`.** Gdy pozycje są złożone w bundle, w `getCart().items` i w payloadach zdarzeń pojawia się tylko kotwica; dzieci przenoszą się do `anchor.bundle.children`. Przestają też liczyć się do `itemCount`.

  **Suma koszyka pozostaje bez zmian**, ponieważ sumy pochodzą prosto z Shopify. Grupowanie zmienia prezentację, nigdy to, co płaci kupujący.
</Warning>

<div id="reading-a-bundle-back">
  ## Odczytywanie bundla
</div>

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.events.on('cart_updated', (state) => {
  state.items.forEach((line) => {
    if (!line.bundle) return;
    console.log(line.title, 'is a bundle of', line.bundle.children.length, 'items:');
    line.bundle.children.forEach((child) => {
      console.log('  ', child.quantity, 'x', child.title);
    });
  });
});
```

Aby działać na pozycjach bundla, użyj `bundle.memberKeys`, który zawiera `key` każdego członka, łącznie z kotwicą.

<div id="using-it-for-other-things">
  ## Użycie do innych rzeczy
</div>

Grupowanie bundli to zastosowanie, dla którego zbudowano `setInternalProperties`, ale nakładka jest ogólnym kanałem dla **danych tylko do renderowania wyprowadzanych z pozycji**. Wszystko, co tam umieścisz, jest czytelne w `line.internalProperties` i w [bloku Custom code](/pl/aftersell/cart/custom-code-blocks), bez dotykania prawdziwego koszyka:

```js theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
window.aftersell.cart.hooks.registerLineTransform((line) => {
  if (line.properties?._preorder_ship_date) {
    line.setInternalProperties({ _badge: `Ships ${line.properties._preorder_ship_date}` });
  }
});
```

Używaj tego, gdy wartość jest **wyprowadzona** i służy tylko do wyświetlania. Jeśli dane mają przetrwać do zamówienia, ich miejsce jest w prawdziwej właściwości pozycji, ustawianej przez ukryty input `properties[...]` w formularzu produktu, dzięki czemu trafia do Shopify niezależnie od tego, kto wykonuje dodanie.

<div id="where-to-go-next">
  ## Co dalej
</div>

* **[`registerLineTransform`](/pl/aftersell/cart/sdk-hooks#registerlinetransform)**: hook, przez który to działa.
* **[Obiekt koszyka](/pl/aftersell/cart/sdk-cart-object#bundles)**: struktura `bundle` i jego dzieci.
* **[Blok Cart items](/pl/aftersell/cart/cart-items-block)**: ustawienie ceny bundla.
