
import SubblyCartFields from "../../../src/reference/cart-widget/types/SubblyCart.mdx";
import SubblyCustomerFields from "../../../src/reference/cart-widget/types/SubblyCustomer.mdx";
import PurchaseFields from "../../../src/reference/cart-widget/types/CheckoutPurchaseResponse.mdx";

<CartWidgetPage group="events" />

Every handler takes two arguments: an error slot first, then the payload. The
widget passes `null` as the error today, so read the second argument. Payloads
are deep-cloned before they are emitted, so a handler cannot change the widget
state through them. `CART_READY` is the exception: it carries the live cart
object.

<Method id="on" signature="subblyCart.events.on(type, handler)">

Subscribes to a widget event. `once` adds a handler for one emission;
`addListener` is an alias of `on`.

<Params>
  <Param name="type" required type="string">
    Name of the event. Use `subblyCart.events.type.CART_UPDATED` and the other
    names below.
  </Param>
  <Param name="handler" required type="(err, payload) => void">
    What to run. The payload shape follows the event.
  </Param>
</Params>

<Returns type="CartEvents">
The emitter, so calls chain.
</Returns>

<Example>

```js title="Listen to an event"
const { events } = subblyCart

events.on(events.type.CART_UPDATED, (err, cart) => {
  console.log(cart.items.length)
})
```

</Example>

</Method>

<Method id="off" signature="subblyCart.events.off(type, handler)">

Removes a handler you added. Pass the same function you passed to `on`.
`removeListener` is an alias; `removeAllListeners(type?)` clears them all.

<Params>
  <Param name="type" required type="string">
    Name of the event.
  </Param>
  <Param name="handler" required type="(err, payload) => void">
    The handler to remove.
  </Param>
</Params>

<Returns type="CartEvents">
The emitter, so calls chain.
</Returns>

<Example>

```js title="Stop listening"
const { events } = subblyCart

const onOpen = () => console.log('open')

events.on(events.type.CART_OPEN, onOpen)
events.off(events.type.CART_OPEN, onOpen)
```

</Example>

</Method>

<Method id="cart-ready" signature="events.type.CART_READY">

The widget finished initializing and the cart is loaded. It fires once, inside
`initialize()`, before that promise resolves with the instance. So no page code
can subscribe in time: neither a listener added after the
`subbly-cart-initialized` window event, nor one added after
`SubblyCart.initialize()` resolves with `init: false`. To act on the loaded
cart, wait for `subbly-cart-initialized` and read `subblyCart.cart`.

This is the one payload the widget does not clone: it is the live cart object.

<Params title="Handler arguments">
  <Param name="err" type="Error | null">
    Always `null`.
  </Param>
  <Param name="cart" type="SubblyCart">
    The loaded cart.

    <Properties label="cart" collapsed>
      <SubblyCartFields />
    </Properties>
  </Param>
</Params>

<Example>

```js title="Read the cart once the widget is ready"
window.addEventListener('subbly-cart-initialized', () => {
  console.log(window.subblyCart.cart.id)
})
```

</Example>

</Method>

<Method id="cart-updated" signature="events.type.CART_UPDATED">

The cart changed. It fires on every change: an item added, updated or removed,
a coupon, a gift card, a currency, an address, a reload, a reset.

<Params title="Handler arguments">
  <Param name="err" type="Error | null">
    Always `null`.
  </Param>
  <Param name="cart" type="SubblyCart">
    The updated cart, as a deep clone.

    <Properties label="cart" collapsed>
      <SubblyCartFields />
    </Properties>
  </Param>
</Params>

<Example>

```js title="Track the item count"
const { events } = subblyCart

events.on(events.type.CART_UPDATED, (err, cart) => {
  document.querySelector('.cart-count').textContent = cart.items.length
})
```

</Example>

</Method>

<Method id="cart-open" signature="events.type.CART_OPEN">

The widget panel opened. It carries no payload.

<Params title="Handler arguments">
  <Param name="err" type="Error | null">
    Always `null`.
  </Param>
</Params>

<Example>

```js title="Listen for the panel opening"
const { events } = subblyCart

events.on(events.type.CART_OPEN, () => {
  document.body.classList.add('cart-open')
})
```

</Example>

</Method>

<Method id="cart-close" signature="events.type.CART_CLOSE">

The widget panel closed. It carries no payload.

<Params title="Handler arguments">
  <Param name="err" type="Error | null">
    Always `null`.
  </Param>
</Params>

<Example>

```js title="Listen for the panel closing"
const { events } = subblyCart

events.on(events.type.CART_CLOSE, () => {
  document.body.classList.remove('cart-open')
})
```

</Example>

</Method>

<Method id="cart-reset" signature="events.type.CART_RESET">

A new cart replaced the old one, after `resetCart()` or after an attempt to add
to a cart that was already purchased. `CART_UPDATED` comes first: the widget
stores the new cart before it emits this event.

<Params title="Handler arguments">
  <Param name="err" type="Error | null">
    Always `null`.
  </Param>
  <Param name="cart" type="SubblyCart">
    The new cart, as a deep clone.

    <Properties label="cart" collapsed>
      <SubblyCartFields />
    </Properties>
  </Param>
</Params>

<Example>

```js title="Notice a new cart"
const { events } = subblyCart

events.on(events.type.CART_RESET, (err, cart) => {
  console.log('new cart', cart.id)
})
```

</Example>

</Method>

<Method id="email-collected" signature="events.type.EMAIL_COLLECTED">

The customer's email was captured. It fires when a guest's email is checked at
the checkout, and when the checkout form opens for a customer who is already
signed in.

<Params title="Handler arguments">
  <Param name="err" type="Error | null">
    Always `null`.
  </Param>
  <Param name="data" type="object">
    The email.

    <Properties label="data">
      <Param name="email" type="string">
        The email address the customer gave.
      </Param>
    </Properties>
  </Param>
</Params>

<Example>

```js title="Send the email to your own tooling"
const { events } = subblyCart

events.on(events.type.EMAIL_COLLECTED, (err, data) => {
  identify(data.email)
})
```

</Example>

</Method>

<Method id="purchase-completed" signature="events.type.PURCHASE_COMPLETED">

A purchase succeeded. Which members of `purchase` are filled depends on the
cart: a future-dated subscription returns the subscription alone, and a cart of
one-time products returns an invoice and orders with no subscription.

<Params title="Handler arguments">
  <Param name="err" type="Error | null">
    Always `null`.
  </Param>
  <Param name="data" type="object">
    The cart that was bought, and what the purchase created.

    <Properties label="data" collapsed>
      <Param name="cart" type="SubblyCart">
        The cart at the moment of the purchase.

        <Properties label="cart" collapsed>
          <SubblyCartFields />
        </Properties>
      </Param>
      <Param name="purchase" type="CheckoutPurchaseResponse">
        What the purchase created.

        <Properties label="purchase" collapsed>
          <PurchaseFields />
        </Properties>
      </Param>
    </Properties>
  </Param>
</Params>

<Example>

```js title="Track a purchase"
const { events } = subblyCart

events.on(events.type.PURCHASE_COMPLETED, (err, data) => {
  const { cart, purchase } = data

  track('purchase', {
    value: purchase.invoice?.total ?? 0,
    currency: cart.currencyCode
  })
})
```

</Example>

</Method>

<Method id="sign-in" signature="events.type.SIGN_IN">

A customer signed in, from the password form, the one-time code form, or
`subblyCart.authenticate()`.

<Params title="Handler arguments">
  <Param name="err" type="Error | null">
    Always `null`.
  </Param>
  <Param name="data" type="object">
    The customer.

    <Properties label="data" collapsed>
      <Param name="customer" type="SubblyCustomer">
        The customer who signed in.

        <Properties label="customer" collapsed>
          <SubblyCustomerFields />
        </Properties>
      </Param>
    </Properties>
  </Param>
</Params>

<Example>

```js title="Greet a returning customer"
const { events } = subblyCart

events.on(events.type.SIGN_IN, (err, data) => {
  console.log('welcome back', data.customer.firstName)
})
```

</Example>

</Method>

<Method id="sign-up" signature="events.type.SIGN_UP">

A customer account was created at the checkout.

<Params title="Handler arguments">
  <Param name="err" type="Error | null">
    Always `null`.
  </Param>
  <Param name="data" type="object">
    The customer.

    <Properties label="data" collapsed>
      <Param name="customer" type="SubblyCustomer">
        The customer who signed up.

        <Properties label="customer" collapsed>
          <SubblyCustomerFields />
        </Properties>
      </Param>
    </Properties>
  </Param>
</Params>

<Example>

```js title="Track a sign-up"
const { events } = subblyCart

events.on(events.type.SIGN_UP, (err, data) => {
  track('sign_up', { customerId: data.customer.id })
})
```

</Example>

</Method>

<Method id="sign-out" signature="events.type.SIGN_OUT">

`subblyCart.signOut()` ran. It carries no payload, and the cart stays as it
is. No control in the widget emits this event, and neither does
`subblyCart.reload()`, which also clears the sign-in state.

<Params title="Handler arguments">
  <Param name="err" type="Error | null">
    Always `null`.
  </Param>
</Params>

<Example>

```js title="Clear your own session"
const { events } = subblyCart

events.on(events.type.SIGN_OUT, () => {
  clearLocalSession()
})
```

</Example>

</Method>
