Home
Wiki
Home
Wiki
  1. 2. Components
  • Back to home
  • 1. Themes
  • Vs Code
    • Getting Started
  • Kitchenware
    • Layout
      • New Layout
      • Legacy Layout
    • Components
      • Announcement
      • Banner Carousel
      • Banner With Products Carousel
      • Blog Category List
      • Blog List
      • Brand List
      • Brands Carousel
      • Breadcrumb
      • Call To Action
      • Cart
      • Categories List
      • Change Password
      • Checkout
      • Cookie Manager
      • Filter list
      • Footer
      • Forgot Password
      • Form
      • Hero Carousel
      • Icon Block
      • Invitation
      • Last Visited Products
      • Layout
      • Login
      • Map
      • Nav Bar
      • Offer
      • Product Attachments
      • Product Attributes
      • Product Documentation
      • Product Expected
      • Product Modal
      • Products Block
      • Products Carousel
      • Product Single
      • Profile
      • Quote
      • Register
      • Related Products
      • Search
      • Stores
      • Subscribe Newsletter
      • Text with Image
      • Top Bar
      • Video
    • Reusables
      • Getting Started
    • Assets
      • Getting Started
    • SDK
      • Products
        • _findProductsByCategory
        • _findProductsByIds
        • _findProductsByTitle
        • _findProductsByFilter
        • _findProductsByCriteria
        • _findProductsAndCalculate
        • _findProductsThenCalculate
        • _getProductAttributeSet
        • _setLastVisited
      • Categories
        • _findCategoryTreeById
        • _findCategoriesByIds
        • _findCategoryByAlias
        • _findCategoryTreeByAlias
        • _getCategoryContent
      • Collections
        • _getCollectionContent
        • _findCollectionsByIds
        • _findCollectionsByIdsThenCalculate
      • Brands
        • _getBrandContent
        • _findBrandsByIds
      • Cart
        • _addToCartMulti
        • _addToCart
        • _setCart
        • _clearCart
        • _setCartListener
        • _removeFromCart
        • _calculateCart
      • Checkout
        • _startCheckout
        • _updateCheckout
        • _completeCheckout
      • Shopping Lists
        • _getShoppingLists
        • _updateShoppingList
        • _createShoppingList
        • _deleteShoppingList
        • _getShoppingListByAlias
      • Navigation
        • _getFooterMenu
        • _getHeaderMenu
      • Users
        • _getUserById
      • Utils
        • _calculateCurrency
        • _getCurrencySymbol
        • _getCulture
        • _subscribeToNewsletter
        • _findUnitsByIds
  • Noir
    • 0. Introduction
    • 6. FAQ
    • 1. Structure
      • _Overview
      • LayoutA.liquid
      • ComponentsList.liquid
      • Metas.liquid
      • CssVariables.liquid
      • Json.liquid
      • GoogleTagManager.liquid
      • StagingButton.liquid
    • 2. Components
      • _Overview
      • Announcement
      • BannerCarousel
      • BlogCategoryList
      • BlogList
      • BrandList
      • Breadcrumb
      • Cart
      • CategoriesList
      • ChangePassword
      • Checkout
      • CookieManager
      • FilterList
      • Footer
      • ForgotPassword
      • Form
      • IconBlock
      • Invitation
      • LastVisitedProducts
      • Login
      • Map
      • NavBar
      • ProductAttachments
      • ProductAttributes
      • ProductComparison
      • ProductDocumentation
      • ProductMixList
      • ProductsBlock
      • ProductsCarousel
      • ProductSingle
      • Profile
      • Quote
      • Register
      • RelatedProducts
      • SingleBlog
      • Stores
      • TextWithImage
      • ThankYouPage
      • TopBar
      • Wishlist
    • 3. Reusables
      • _Overview
      • Addresses
      • AddressForm
      • AnnouncementModal
      • BackToTop
      • BillingRetail
      • Company
      • General
      • Login
      • LoginModal
      • MonthlyTransactions
      • Orders
      • Payment
      • ProductAttachments
      • ProductAttributes
      • ProductComparisonButton
      • ProductComparisonFloatingButton
      • ProductGridItem
      • ProductListItem
      • ProductModal
      • ProfileInfo
      • PromptModal
      • Quotes
      • Register
      • Services
      • Shipping
      • ShoppingLists
      • ShoppingListsButton
      • ShoppingListsNavbar
      • Toast
      • Transactions
      • Users
      • VariantContent
      • WishlistButton
    • 4. Assets
      • Fonts
      • Images
      • Templates
      • Javascript
        • _Overview
        • theme.js
      • Css - Scss
        • _Overview
        • ThemeClasses
    • 5. SDK
      • _Overview
      • LiquidGlobals
      • ServicesSDK
  1. 2. Components

Checkout

Purpose#

The Checkout component renders and orchestrates the checkout experience.
It supports:
Rendering different checkout states:
payment cancelled (pageState == 'cancel')
payment ok but order creation failed (pageState == 'error')
normal checkout flow (default)
Billing / Shipping / Payment sections (rendered via Reusables and gated by checkout settings flags)
Order summary (cart items, totals, line notes if enabled)
Coupons handling (add/remove)
Points redemption (enable/disable)
Completing checkout (proceed to payment/order)
Redirect flow on success

Inputs (model contract)#

Model shape (storefront example)#

{
  "pageState": null,
  "status": "Start",
  "checkout": {
    "netValue": 0,
    "netValueText": "0.00 €",
    "vatValue": 0,
    "vatValueText": "0.00 €",
    "finalPrice": 0,
    "finalPriceText": "0.00 €",
    "billingAddress": {
      "id": "Address Id",
      "name": "Sample name",
      "firstName": "Sample first name",
      "lastName": "Sample last name",
      "phoneNumber": "Sample phone",
      "address1": "Sample address",
      "city": "Sample city",
      "state": "Sample state",
      "country": "Sample country",
      "countryCode": "XX",
      "postalCode": "Sample postal code",
      "email": "sample@example.com"
    },
    "shippingAddress": {
      "id": "Address Id",
      "name": "Sample name",
      "firstName": "Sample first name",
      "lastName": "Sample last name",
      "phoneNumber": "Sample phone",
      "address1": "Sample address",
      "city": "Sample city",
      "state": "Sample state",
      "country": "Sample country",
      "countryCode": "XX",
      "postalCode": "Sample postal code",
      "email": "sample@example.com"
    },
    "cartItems": [
      {
        "id": "Cart line Id",
        "productId": "Product Id",
        "productVariantId": "Variant Id",
        "quantity": 1,
        "productTitle": "Sample product title",
        "link": "sample-product-link",
        "imageLink": "https://example.com/sample",
        "finalPrice": 0,
        "finalPriceText": "0.00 €",
        "originalPrice": 0,
        "originalPriceText": "0.00 €",
        "subTotalNetValue": 0,
        "subTotalPrice": 0,
        "subTotalVatValue": 0
      },
      ...
    ],
    "pricingBeforeDiscount": {
      "netValue": 0,
      "netValueText": "0.00 €",
      "vatValue": 0,
      "vatValueText": "0.00 €",
      "finalPrice": 0,
      "finalPriceText": "0.00 €"
    }
  },
  "carriers": {
    "globalConfig": {
      "freeAtPrice": 0,
      "freeAtPriceText": "0.00 €",
      "freeAtWeightText": " kg"
    },
    "list": [
      {
        "carrierId": "Carrier Id",
        "carrierCode": "sample",
        "title": "Sample carrier title",
        "type": "Manual",
        "netPrice": 0,
        "totalAmount": 0,
        "totalAmountText": "0.00 €",
        "vatLines": []
      },
      ...
    ]
  },
  "payments": [
    {
      "provider": "Sample provider",
      "providerId": "Provider Id",
      "name": "Sample payment name",
      "message": "<p>Sample message</p>",
      "installmentsEnabled": false
    },
    ...
  ],
  "deliveryZonesEnabled": true,
  "countriesList": [
    {
      "code": "XX",
      "name": "Sample country name"
    },
    ...
  ],
  "addresses": [
    {
      "name": "",
      "isSelectable": true,
      "address": {
        "id": "Address Id",
        "firstName": "Sample first name",
        "lastName": "Sample last name",
        "phoneNumber": "Sample phone",
        "address1": "Sample address",
        "city": "Sample city",
        "state": "Sample state",
        "country": "Sample country",
        "countryCode": "XX",
        "postalCode": "Sample postal code",
        "email": "sample@example.com"
      },
      "requiresInvoice": false
    },
    ...
  ],
  "name": "Checkout",
  "view": "Default",
  "section": "SectionA",
  "settings": {
    "id": "Component Id",
    "section": "SectionA",
    "type": "NoirCheckout",
    "name": "Checkout",
    "configuredInContentApi": true,
    "view": "Default",
    "displayName": "Sample display name",
    "cssClass": ""
  },
  "translations": {
    "completeOrder": "Sample translation",
    "backToCart": "Sample translation",
    "orderSummary": "Sample translation",
    "...": "..."
  }
}

Required fields#

settings.id
Used for wrapper id: comp-{{ id }}
checkout
Main checkout object used throughout the UI and passed into JS as serialized data.

Optional fields#

settings.cssClass
Applied to wrapper only when non-empty and not (UNDEFINED).
pageState
Controls which layout is rendered:
cancel → Payment cancelled/failed page
error → Order creation failed page
otherwise → normal checkout
addresses, countriesList
Used by Billing/Shipping reusables.
carriers, payments
Used by Shipping/Payment reusables.

JavaScript#

Global object#

The component exposes a global object:
It’s initialized from Liquid via Alpine:
x-data='checkoutdefault.initComponent({{ checkout | serialize | escape }})'
initComponent(...) returns the Alpine component state + methods for:
initializing checkout state
coupon and points operations (via servicesreusabledefault.updateCheckout(...))
completing checkout (via servicesreusabledefault.proceedToCheckout(...))
optional UI helpers (validity checks, IntersectionObserver for the aside button)

initComponent#

Factory that receives the serialized checkout object and returns the Alpine state + handlers.

init#

Runs on Alpine mount. It reads the checkoutToken from cookies, stores it in localStorage, initializes Alpine.store("checkout"), and sends GA beginCheckout when cart data exists.

createObserver#

Creates or refreshes an IntersectionObserver that tracks whether the aside “Complete order” button is visible, and stores the result in isAsideButtonVisible.

checkValidity#

Sets validCheckout based on whether the consent checkbox #concent-order is checked.

handlePoints#

Toggles points redemption and persists the updated checkout via servicesreusabledefault.updateCheckout(this.checkout).

handleCoupons#

Returns a nested Alpine object dedicated to coupon UI state.
couponValue#
Computed getter that returns the current coupon string (the implementation joins the list with ;).
addCoupon#
Validates input and adds a coupon (async).
handleBackspace#
Backspace handler that can remove the active coupon.
removeCoupon#
Removes a coupon by index (async).
removeCoupons#
Removes all coupons (async).

addCoupon#
Guard clauses: returns if:
input is empty, or
already adding (this.isCouponAdding)
Clears toasts.
Resets UI state:
stores couponLastInput
clears status
sets state = "default"
sets isCouponAdding = true
resets this.coupons = []
Builds loyaltyPricing:
usePoints: this.isPointsRedeemed
useCoupon: true
couponCodes: [couponInput]
Assigns to this.checkout.loyaltyPricing, then calls:
servicesreusabledefault.updateCheckout(this.checkout)
On HTTP/service failure:
shows toast with addCouponErrorMessage
On success:
updates this.checkout = response.data
if checkout.loyaltyPricing.errorCode exists:
sets state = "invalid"
maps backend errorCode to a UI couponStatus string (e.g. invalidCode, alreadyUsedCode, discountExceeded, etc.)
else (valid coupon):
sets state = "valid"
sets this.isCouponRedeemed = true
pushes coupon into this.coupons
sets couponStatus = "validCode"
stores couponLabel and couponsDiscountText from checkout response
Always clears isCouponAdding in finally.
The method catches errors and logs to console but doesn’t toast a generic error. If you want consistent UX, toast on catch as well.
Coupon codes are treated as raw strings; trim before sending to avoid whitespace issues.

handleBackspace#
If input is empty and there is at least one coupon in the list:
removes the last coupon by calling removeCoupon(lastIndex, ...)
This is a UX shortcut; keep it only if it matches your design guidelines. It can surprise users if they hit backspace and coupons disappear.

removeCoupon#
Clears toasts.
Removes coupon at index from this.coupons.
Updates this.checkout.loyaltyPricing:
useCoupon = hasCoupons
couponCodes = this.coupons
Calls:
servicesreusabledefault.updateCheckout(this.checkout)
On failure:
shows toast with removeCouponErrorMessage
On success:
updates this.checkout = response.data
sets state to "invalid" if there are still coupons and backend returns errorCode, else "default"
updates couponsDiscountText from response
Current behavior keeps points state intact via the existing checkout.loyaltyPricing object; make sure points-related flags don’t get lost when refactoring.

removeCoupons#
Clears toasts.
Sets isCouponAdding = true (re-using the “busy” flag).
Builds a loyaltyPricing object:
usePoints: this.isPointsRedeemed
useCoupon: false
couponCodes: []
Calls updateCheckout.
On failure:
shows toast, clears isCouponAdding, returns.
On success:
updates checkout
resets coupon UI state to defaults:
state = "default"
isCouponRedeemed = false
clears coupons list and discount text/status/labels
clears isCouponAdding
Resetting many fields here is intentional to keep UI consistent. If you add new coupon-related state fields later, remember to reset them here too.

sendSelectEvent#

Sends GA “select item” event:
prepares item via prepareListProducts([item])
calls sendGAEvent("selectItem", { listName, items, position })
Keep analytics event naming consistent with the rest of the theme (selectItem, beginCheckout, etc.).

completeCheckout#

Final step to place the order / proceed to payment:
1.
Clears toasts.
2.
Reads the latest checkout state from store:
const checkoutData = Alpine.store("checkout").data;
3.
Copies addresses/invoice from the store into this.checkout:
billingAddress, shippingAddress, invoiceData
4.
Sets this.isCompleting = true
5.
Calls:
servicesreusabledefault.proceedToCheckout(this.checkout)
6.
On failure:
shows toast with completeCheckoutErrorMessage
clears isCompleting and returns
7.
On success:
updates this.checkout = response.data
clears isCompleting
8.
If this.checkout.status == "Completed":
sets isRedirecting = true
reads token from localStorage
clears cart + checkout tokens from localStorage
clears cookies (cartToken, checkoutToken)
redirects to:
/checkout/order-completed/<checkoutToken>
This assumes the checkout store is always up-to-date. If a reusable updates store state asynchronously, ensure it’s committed before calling complete.
Clearing storage is critical to prevent stale cart/checkout in subsequent sessions.
If proceedToCheckout returns a payment redirect URL (for card payments), you may need to handle that case separately; current logic focuses on status == "Completed".

Global Alpine stores (used by Checkout)#

Alpine.store("checkout")#

(checkout shared state)
The template/codebase may also reference this store via $store.checkout.
Checkout uses a global store to share updated addresses/invoice data with the final “complete order” action.
Key usage:
On init:
Alpine.store("checkout").set(this.checkout)
On complete:
reads Alpine.store("checkout").data
copies billing/shipping/invoice into this.checkout before proceeding
This store allows reusables (Billing/Shipping/Payment) to update the checkout state in one place.

Alpine.store("toast")#

(user feedback)
Used for:
coupon errors
points redemption errors
checkout completion errors
general update errors
Common pattern:
Alpine.store("toast").removeAll();
Alpine.store("toast").add(message, "ic-warning", "error");

Services / API calls#

Checkout calls the services layer for key operations:
servicesreusabledefault.updateCheckout(checkout)
Used when:
enabling/disabling points
adding/removing coupons
recalculating totals after loyalty pricing changes
servicesreusabledefault.proceedToCheckout(checkout)
Used when user confirms the order (final step).
On success (checkout.status == "Completed"), it:
clears cart + checkout tokens from local storage/cookies
redirects to:
/checkout/order-completed/<checkoutToken>

Dependencies#

Alpine.js
Alpine stores: checkout, toast
Cookies/localStorage:
checkoutToken cookie
cartData localStorage (GA + summary consistency)
Services layer methods:
updateCheckout(...)
proceedToCheckout(...)

Notes#

Checkout requires a checkoutToken available in cookies. If missing, init throws an error.
Coupons UI currently supports a single coupon input flow (the code includes TODO comments for multi-coupon support).
On successful completion, the component clears cart-related storage. This is important to avoid stale cart state after placing an order.

Extras#

Template behavior (Liquid + Alpine)#

State-driven rendering#

If pageState == 'cancel' → renders a “payment failed/cancelled” UI and CTA back to checkout.
If pageState == 'error' → renders a “checkout error” UI and CTA back to checkout.
Else → renders the normal checkout flow and initializes JS with:
x-data='checkoutdefault.initComponent({{ checkout | serialize | escape }})'

Sections rendered via Reusables#

The template renders these blocks depending on checkout settings flags:
Billing (Reusables\\BillingRetail\\Default)
Shipping (Reusables\\Shipping\\Default)
Payment (Reusables\\Payment\\Default)
Visibility is controlled by config flags (injected globally as window.checkoutConfig and also available as Liquid settings).

Coupons area#

If coupons are enabled via global settings, the template renders the coupons UI, which is controlled by the JS helper handleCoupons().

Order summary#

Renders checkout cart items and totals, and optionally product line notes if enabled by global settings.
Modified at 2026-05-12 07:10:29
Previous
ChangePassword
Next
CookieManager
Built with