# `hb-checkout-shopping-cart`

**Category:** commerce · **Tags:** commerce, cart

Shopping-cart **order summary** for checkout flows. It aggregates line items from a `payment` payload, shows **subtotal**, **tax**, optional **shipping**, and **grand total**, and renders the line list with **`hb-table`** (pagination disabled). Styling uses **Bulma** tokens on `:host` and **Bootstrap Icons** for the cart title icon.

---

## Custom element

```html
<hb-checkout-shopping-cart></hb-checkout-shopping-cart>
```

Tag name: **`hb-checkout-shopping-cart`**

---

## Runtime dependency

The component registers **`hb-table`** via the shared component loader (`addComponent` for `@htmlbricks/hb-table` at the same version as the bundle). Your page or bundle must load **`hb-table`** so the inner `<hb-table>` custom element is defined. See `extra/docs.ts` → `componentSetup.dependencies` for the full nested dependency graph used by the table package.

---

## Attributes and properties (HTML integrators)

Web component attributes are **strings**. Complex data is passed as **JSON strings**. Booleans use **`yes`** / **`no`** where applicable.

| Name | Required | Description |
| --- | --- | --- |
| `payment` | Yes (for a meaningful cart) | JSON string describing the cart and pricing context. See [Payment payload](#payment-payload) below. |
| `completed` | No | `"yes"` or `"no"` (default **`no`**). Reserved in the public typings; the current implementation does **not** change layout or copy when set to `"yes"`. |
| `id` | No | Present in typings for API consistency; not applied to the visible root in the current markup (inner layout uses a fixed `id="page"`). |

From HTML, set `payment` as a **single-quoted** attribute whose value is JSON, or assign the property from JavaScript (`element.payment = { ... }`).

---

## Payment payload

TypeScript shape (authoring / wrappers):

```ts
interface IShopItem {
  id: string;
  unit?: string;
  name: string;
  unitaryPrice: number;
  taxPercentage: number;
  quantity?: number;
}

interface IShoppingPayment {
  countryCode: "IT" | "US" | "EU";
  currencySymbol?: "€" | "$";
  shipmentFee?: number;
  items: IShopItem[];
}
```

### Field notes

- **`countryCode`**: Drives default **`currencySymbol`** when it is omitted: `IT` and `EU` → `€`, `US` → `$`.
- **`currencySymbol`**: Shown next to monetary amounts. If missing after parse, it is filled from `countryCode` as above.
- **`shipmentFee`**: Optional number added to **grand total**. If absent, the shipping row shows **`-`** (no fee).
- **`items`**: Each line needs **`id`**, **`name`**, **`unitaryPrice`**, and **`taxPercentage`**. **`quantity`** defaults to **1** if omitted. **`unit`** is optional; if missing, the per-line price suffix uses the Italian word **unità** in the table’s price column.

If `payment` is missing or invalid, the component falls back to `{ countryCode: "IT", currencySymbol: "€", items: [] }`.

When `payment` arrives as a **string** (typical from `setAttribute`), it is **`JSON.parse`d**; missing `countryCode` defaults to **`IT`**, and `currencySymbol` is inferred from `countryCode` if still missing.

---

## How totals are calculated

- **Subtotal**: Sum of `unitaryPrice * (quantity ?? 1)` over all items.
- **Tax total**: Sum of per-line `unitaryPrice * (quantity ?? 1) * (taxPercentage / 100)`, then the **sum** is rounded to two decimal places (not each line before summing).
- **Grand total**: `subtotal + taxTotal + (shipmentFee ?? 0)`.

Per-row **line total** in the table uses **tax rounded per line** to two decimals before adding to the pre-tax line amount, which can differ slightly from the aggregate tax total above.

---

## Inner table

`<hb-table>` is used with:

- `disablepagination="yes"`
- `rows` and `headers` passed as **JSON strings** built from `payment.items`.

Column headers (labels are **Italian** in the current source): name (**nome**), quantity (**n.**), line total (**totale**). Summary rows above the table are also Italian (**SubTotale**, **Tasse**, **Spedizione**, **Totale**). There is **no i18n** package hook for this component in `extra/docs.ts`.

---

## CSS custom properties

Theme via [Bulma CSS variables](https://bulma.io/documentation/features/css-variables/) and the host-specific token below.

| Variable | Type | Default | Role |
| --- | --- | --- | --- |
| `--bulma-text` | color | `#363636` | Title and summary text. |
| `--bulma-border` | color | `#dbdbdb` | Base color for the divider; feeds `--hb-checkout-border` if you do not override it. |
| `--hb-checkout-border` | border shorthand | `1px solid` + `var(--bulma-border, …)` | Top border of the block above the line-items table (`.cart_divider`). |

### `::part` and slots

- **CSS parts:** none (`styleSetup.parts` is empty).
- **Slots:** none.

---

## Events

`Events` in `types/webcomponent.type.d.ts` is **empty**: the component does **not** declare custom events in the public typings.

---

## Examples

### Minimal cart (HTML)

```html
<hb-checkout-shopping-cart
  payment='{"countryCode":"IT","currencySymbol":"€","items":[{"id":"sku-1","name":"T-shirt","unitaryPrice":19.99,"taxPercentage":22,"quantity":2}]}'
  completed="no"
></hb-checkout-shopping-cart>
```

### With shipping and explicit quantity

```html
<hb-checkout-shopping-cart
  payment='{"countryCode":"EU","currencySymbol":"€","shipmentFee":5.5,"items":[{"id":"a","name":"Poster","unitaryPrice":12,"taxPercentage":10,"quantity":2}]}'
></hb-checkout-shopping-cart>
```

### From JavaScript (object property)

```js
const el = document.querySelector("hb-checkout-shopping-cart");
el.payment = {
  countryCode: "US",
  items: [
    { id: "x", name: "Item", unitaryPrice: 10, taxPercentage: 8, quantity: 1 },
  ],
};
```

---

## Summary for integrators

- Pass **`payment`** as JSON (string from HTML, object from JS); align with **`IShoppingPayment`** / **`IShopItem`**.
- Expect **Italian** labels in the UI; no built-in language switching.
- Style with **`--bulma-*`** and **`--hb-checkout-border`** on the host.
- Ensure **`hb-table`** (and its dependencies) are loaded with your bundle.
- **`completed`**: accepted but **no visible “order placed” mode** in the current `component.wc.svelte` implementation—treat as forward-compatible only unless you fork or extend the component.
