Skip to main content

Discounts

Discount and coupon code management components for e-commerce applications.

Purpose

This library provides headless, flexible components for managing discounts, coupon codes, and promotional offers in e-commerce applications. It enables applying coupon codes, displaying active discounts, and removing promotional codes from orders.

Features

  • Coupon code application and validation
  • Active discount display with promotion details
  • Discount removal functionality
  • Headless component architecture for full customization
  • Error handling and loading states
  • Accessibility-first design

Installation

npm install @haus-storefront-react/discounts

Note: This is not a public package. Contact the Haus Tech Team for access.

API Reference

CouponCode.Root

The main container component that provides coupon code context to all child components. Uses a render function pattern to pass context values.

Props

PropTypeRequiredDefaultDescription
childrenChildrenProps<UseCouponCodeReturn>No-Render function that receives the coupon code context

CouponCode.Input

Text input component for entering coupon codes. Automatically handles Enter key to apply the coupon code. Disables during loading state and supports all standard HTML input attributes.

Props

PropTypeRequiredDefaultDescription
placeholderstringNo-Placeholder text
disabledbooleanNofalseDisabled state

Behavioral Notes:

  • Enter key triggers coupon code application
  • Automatically disabled when isLoading is true
  • Controlled component managed by internal context

CouponCode.ApplyButton

Button component to apply the entered coupon code. Automatically disabled when no code is entered or while loading.

Behavioral Notes:

  • Automatically disabled when isLoading is true or when code is empty
  • Children receive { isLoading, error } as render props

CouponCode.RemoveButton

Button component to remove a specific coupon code from the order.

Props

PropTypeRequiredDefaultDescription
couponCodestringYes-The coupon code to remove
asChildbooleanNofalseUse a custom component instead of the default button

Behavioral Notes:

  • Automatically disabled when isLoading is true
  • Triggers removal of the specified coupon code from the active order

CouponCode.Error

Component for displaying error messages. Only renders when an error is present.

Behavioral Notes:

  • Returns null if no error is present
  • Displays error.message if no children are provided

CouponCode.Display

Component for displaying applied coupon codes with optional discount information.

Props

PropTypeRequiredDefaultDescription
couponCodestringYes-The coupon code to display
discountstringNo-Optional discount amount or description
asChildbooleanNofalseUse a custom component instead of the default div

Behavioral Notes:

  • Children receive { couponCode, discount } as render props

ActiveDiscounts.Root

The main container component that provides active discounts context. Uses a render function pattern to pass context values.

Props

PropTypeRequiredDefaultDescription
childrenChildrenProps<ActiveDiscountsContextValue>No-Render function that receives the active discounts context

ActiveDiscounts.List

Container component for the list of active discounts. Automatically returns null if there are no discounts.

Behavioral Notes:

  • Returns null if discounts is empty or undefined
  • Children receive { discounts } as render props

ActiveDiscounts.Item

Container component for individual discount items. Provides discount-specific context to children.

Props

PropTypeRequiredDefaultDescription
discountDiscountWithPromotionYes-The discount object to display
asChildbooleanNofalseUse a custom component instead of the default div

Behavioral Notes:

  • Children receive { discount } as render props
  • Creates a nested context with the current discount for RemoveButton to access

ActiveDiscounts.RemoveButton

Button component to remove a coupon code discount. Only renders if the discount has an associated promotion with a coupon code.

Behavioral Notes:

  • Returns null if the discount does not have a promotion.couponCode
  • Must be used within an ActiveDiscounts.Item to access the current discount
  • Automatically removes the coupon code associated with the discount

useCouponCode

Hook for managing coupon code application and removal. Provides state management and functions for interacting with the active order's coupon codes.

Parameters

This hook takes no parameters.

Returns

Return ValueTypeDescription
codestringCurrent coupon code input value
isLoadingbooleanLoading state flag for API operations
errorError | nullError object if coupon code application failed
setCode(code: string) => voidFunction to update the coupon code input value
applyCouponCode(code: string) => Promise<void>Function to apply a coupon code to the active order
removeCouponCode(code: string) => Promise<void>Function to remove a coupon code from the active order

useActiveDiscounts

Hook for retrieving and managing active discounts on the current order. Automatically maps order discounts with their associated promotions.

Parameters

This hook takes no parameters.

Returns

Return ValueTypeDescription
discountsDiscountWithPromotion[]Array of active discounts with promotion details
removeCouponCode(couponCode: string) => Promise<void>Function to remove a coupon code (delegates to useCouponCode)

Basic Usage

Simple Coupon Code Application

import { CouponCode } from '@haus-storefront-react/discounts'

function CouponSection() {
return (
<CouponCode.Root>
<CouponCode.Input placeholder='Enter coupon code' />
<CouponCode.ApplyButton>Apply</CouponCode.ApplyButton>
<CouponCode.Error />
</CouponCode.Root>
)
}

Basic Hook Usage

import { useCouponCode } from '@haus-storefront-react/discounts'

function MyComponent() {
const { code, isLoading, applyCouponCode } = useCouponCode()

const handleApply = async () => {
await applyCouponCode(code)
}

if (isLoading) return <div>Applying...</div>

return <button onClick={handleApply}>Apply Coupon</button>
}

Display Active Discounts

import { ActiveDiscounts } from '@haus-storefront-react/discounts'

function DiscountDisplay() {
return (
<ActiveDiscounts.Root>
<ActiveDiscounts.List>
{({ discounts }) => (
<>
{discounts.map((discount, index) => (
<ActiveDiscounts.Item key={index} discount={discount}>
{({ discount }) => <div>{discount.description}</div>}
</ActiveDiscounts.Item>
))}
</>
)}
</ActiveDiscounts.List>
</ActiveDiscounts.Root>
)
}

Advanced Usage

Complete Checkout Discount Section

import { CouponCode, ActiveDiscounts, useCouponCode, useActiveDiscounts } from '@haus-storefront-react/discounts'
import { Price } from '@haus-storefront-react/common-ui'

function CheckoutDiscountSection() {
const { code, isLoading: couponLoading, error: couponError } = useCouponCode()
const { discounts, removeCouponCode } = useActiveDiscounts()

return (
<div className="checkout-discounts">
<CouponCode.Root>
{(couponContext) => (
<div>
<CouponCode.Input
placeholder="Enter coupon code"
disabled={couponLoading}
/>
<CouponCode.ApplyButton>
{({ isLoading }) => (
isLoading ? 'Applying...' : 'Apply Coupon'
)}
</CouponCode.ApplyButton>
<CouponCode.Error>
{(error) => error && (
<div className="error">
{error.message}
</div>
)}
</CouponCode.Error>
</div>
)}
</CouponCode.Root>

{discounts.length > 0 && (
<ActiveDiscounts.Root>
{(activeDiscountsContext) => (
<ActiveDiscounts.List>
{({ discounts }) => (
<div>
<h3>Active Discounts</h3>
{discounts.map((discount, index) => (
<ActiveDiscounts.Item key={index} discount={discount}>
{({ discount }) => (
<div className="discount-item">
<div>
<span>{discount.description}</span>
{discount.promotion?.couponCode && (
<span className="coupon-code">
Code: {discount.promotion.couponCode}
</span>
)}
</div>
<ActiveDiscounts.RemoveButton>
Remove
</ActiveDiscounts.RemoveButton>
<Price.Root
price={discount.amount}
priceWithTax={discount.amountWithTax}
currencyCode={discount.currencyCode}
>
<Price.Amount withCurrency />
</Price.Root>
</div>
))}
</div>
)}
</div>
)}
</ActiveDiscounts.List>
)}
</ActiveDiscounts.Root>
)}
</div>
)
}

Conditional Rendering Patterns

import {
CouponCode,
ActiveDiscounts,
useCouponCode,
useActiveDiscounts,
} from '@haus-storefront-react/discounts'

function ConditionalDiscountUI() {
const { code, isLoading: couponLoading, error } = useCouponCode()
const { discounts, removeCouponCode } = useActiveDiscounts()

if (couponLoading) {
return <div>Loading...</div>
}

if (discounts.length === 0) {
return (
<CouponCode.Root>
{(context) => (
<div>
<CouponCode.Input placeholder='Add a coupon code' />
<CouponCode.ApplyButton>Apply</CouponCode.ApplyButton>
{error && (
<CouponCode.Error>
<div>{error.message}</div>
</CouponCode.Error>
)}
</div>
)}
</CouponCode.Root>
)
}

return (
<div>
<CouponCode.Root>
{(context) => (
<div>
<CouponCode.Input placeholder="Add another coupon" />
<CouponCode.ApplyButton>Apply</CouponCode.ApplyButton>
</div>
)}
</CouponCode.Root>

<ActiveDiscounts.Root>
{(activeDiscountsContext) => (
<ActiveDiscounts.List>
{({ discounts }) => (
<div>
<h3>Your Discounts</h3>
{discounts.map((discount, index) => (
<ActiveDiscounts.Item key={index} discount={discount}>
{({ discount }) => (
<div>
<span>{discount.description}</span>
<ActiveDiscounts.RemoveButton>
Remove
</ActiveDiscounts.RemoveButton>
</div>
)}
</ActiveDiscounts.Item>
))}
</div>
)}
</ActiveDiscounts.List>
)}
</ActiveDiscounts.Root>
</div>
)
}

Made with ❤️ by Haus Tech Team