Skip to main content

OrderItemCard

A display-only component that renders a single line item within an order or quotation table. It shows product details (image, name, SKU), quantity, pricing, discounts, and optional notes. Supports parent/child item grouping for bundled products.

Usage

Basic order detail table

import OrderItemCard from '@/components/propeller/OrderItemCard';

<table className="w-full">
<thead>
<tr>
<th>Product</th>
<th>Quantity</th>
<th>Price</th>
</tr>
</thead>
{items.map((item) => (
<OrderItemCard key={item.id} orderItem={item} />
))}
</table>

With parent/child grouping and discounts (quotes page)

import OrderItemCard from '@/components/propeller/OrderItemCard';

// Separate parent items from child items
const parentItems = allProducts.filter((item) => !item.parentOrderItemId);
const childMap = new Map();
allProducts
.filter((item) => item.parentOrderItemId)
.forEach((item) => {
const children = childMap.get(item.parentOrderItemId) || [];
children.push(item);
childMap.set(item.parentOrderItemId, children);
});

<table className="w-full">
<thead>
<tr>
<th>Products</th>
<th>Quantity</th>
<th>Discount</th>
<th>Price</th>
</tr>
</thead>
{parentItems.map((item) => (
<OrderItemCard
key={item.id}
orderItem={item}
showDiscount={true}
childItems={childMap.get(item.id) || []}
/>
))}
</table>

Minimal display for surcharges or fee lines

<OrderItemCard
orderItem={feeItem}
titleLinkable={false}
showImage={false}
showSku={false}
/>

With custom price formatting

<OrderItemCard
orderItem={item}
formatPrice={(price) => `$ ${price.toFixed(2)}`}
/>

Non-linkable items (bonus items, promotions)

<OrderItemCard orderItem={item} titleLinkable={false} />

With notes and stock info visible

<OrderItemCard
orderItem={item}
showItemNotes={true}
showStockComponent={true}
/>

Configuration

Core Data

PropTypeRequiredDefaultDescription
orderItemanyYes--The order item object to display. See "Order Item Fields" below for expected shape.
childItemsany[]No[]Child/bundled items rendered as indented sub-rows beneath the parent row.

Display Toggles

PropTypeDefaultDescription
titleLinkablebooleantrueRender the product name as a link to the product detail page. Falls back to plain text if the product has no productId or slug.
showImagebooleantrueShow a 64x64 product thumbnail. Forced to false when isChildItem is true.
showSkubooleantrueShow the SKU beneath the product name. Forced to false when isChildItem is true.
showQuantitybooleantrueShow the quantity column.
showPricebooleantrueShow the total price column.
showDiscountbooleanfalseShow the discount column with amount and percentage.
showItemNotesbooleanfalseShow the item notes text beneath the product name.
showStockComponentbooleanfalseShow a stock info placeholder beneath the product name.

Rendering Mode

PropTypeDefaultDescription
isChildItembooleanfalseRender as an indented sub-item with smaller text, no image, and no SKU. Used internally when rendering child items, but can be set manually.

Formatting

PropTypeDefaultDescription
formatPrice(price: number) => stringFormats as €{price.toFixed(2)}Custom price formatting function applied to all price values in the component.

Order Item Fields

This component is display-only and does not call any SDK services. It reads the following fields from the orderItem object (typically an OrderItem from the Propeller SDK):

Product Information

Field PathPurpose
orderItem.product.names[0].valueProduct display name (primary source)
orderItem.nameProduct display name (fallback)
orderItem.product.skuProduct SKU (primary source)
orderItem.skuProduct SKU (fallback)
orderItem.product.productIdUsed to build the product detail page URL
orderItem.product.slugs[0].valueUsed to build the product detail page URL
orderItem.product.media.images.items[0].imageVariants[0].urlProduct thumbnail URL

Pricing and Quantity

Field PathPurpose
orderItem.quantityItem quantity
orderItem.priceUnit price
orderItem.priceTotalTotal price for the line (displayed in the price column)
orderItem.discountDiscount amount
orderItem.originalPriceOriginal price before discount (used to calculate discount percentage)

Other

Field PathPurpose
orderItem.notesItem-level notes (shown when showItemNotes is enabled)
orderItem.parentOrderItemIdIdentifies child items -- items with this field set belong to a parent item
orderItem.idUsed as the React key when rendering

Child items read a subset: product.names[0].value, name, quantity, priceTotal, id, and uuid.


Behavior

HTML Structure

The component renders a <tbody> element containing one or more <tr> rows. Because of this, it must be placed directly inside a <table> -- do not wrap it in another <tbody>.

Child Items

Items with a parentOrderItemId are children belonging to a parent item. The parent page is responsible for:

  1. Filtering parent items (those without parentOrderItemId)
  2. Building a lookup of parentId -> childItems[]
  3. Passing the children via the childItems prop on the parent's OrderItemCard

Child rows render with left indentation (pl-28), smaller text, no border, no image, and no discount. They share the parent's column visibility settings for quantity and price.

Price Display

  • The price column shows priceTotal (the line total), not the unit price.
  • Default formatting is followed by two decimal places (e.g., €127.50).
  • Pass formatPrice to override formatting for all prices in the component (unit prices, totals, and discount amounts).

Discount Display

When showDiscount is true:

  • Shows the discount amount formatted by formatPrice, followed by the percentage in parentheses: e.g., €127.50 (15,00%)
  • Percentage is calculated as (discount / originalPrice) * 100
  • The percentage uses comma as decimal separator
  • Rendered in orange text
  • Empty cell when the item has no discount
  • Child items never show discount values

Image Handling

  • Displays a 64x64 thumbnail from the first image variant of the first media image
  • When no image URL is available, shows a gray placeholder with "No Img" text
  • Images are hidden entirely when showImage is false or when rendering a child item
  • The compiled React version uses Next.js Image and Link components instead of plain HTML tags

Title Linking

  • When titleLinkable is true (default), the product name links to /product/{productId}/{slug}
  • If the product lacks a productId or slug, the title falls back to plain text automatically
  • Child items never render as links, regardless of the titleLinkable setting

Stock Info

The showStockComponent prop renders a placeholder text. Replace it with an actual stock display component as needed for your application.