Skip to main content

Overview

The OrderCard component renders an individual order as a visually distinct card within the kanban board. It displays essential order information including partner details, order number, priority level, and active timer, with color-coded styling based on the order’s current status.

Props Interface

type OrderCardProps = {
  order: OrderListDto;
  onClick?: () => void;
  isOverlay?: boolean;
};
order
OrderListDto
required
The order data object containing all information to display.OrderListDto Structure:
type OrderListDto = {
  id: string;
  partnerName?: string;
  partnerImage?: string;
  displayNumber: string;
  status: OrderStatus;
  priority: OrderPriority; // "NORMAL" | "HIGH"
  activeTimer?: string;
  courierName?: string;
}
onClick
() => void
Optional callback function invoked when the card is clicked. Typically used to open order details.
isOverlay
boolean
default:"false"
When true, applies special styling for drag overlay rendering. Used during drag-and-drop operations.

Visual Features

Status Colors

Each order status has a unique color scheme for instant visual recognition

Priority Badge

High-priority orders display a prominent badge

Active Timer

Shows how long the order has been in its current status

Partner Logo

Displays partner branding when available

Status-Based Styling

The component applies different CSS classes based on the order status:
const STATUS_CLASS: Record<OrderStatus, string | undefined> = {
  RECEIVED: s.received,
  CONFIRMED: s.confirmed,
  PREPARING: s.preparing,
  READY: s.ready,
  PICKED_UP: s.pickedUp,
  DELIVERED: s.delivered,
  CANCELLED: s.cancelled,
};
Initial status when an order enters the system. Typically styled with a neutral or info color.

Component Structure

export default function OrderCard({
  order,
  onClick,
  isOverlay = false,
}: OrderCardProps) {
  const isHighPriority = order.priority === "HIGH";
  
  return (
    <Card
      size="md"
      variant="elevated"
      className={clsx(
        s.card,
        STATUS_CLASS[order.status],
        isOverlay && s.overlay,
      )}
      onClick={(e) => {
        e.stopPropagation();
        onClick?.();
      }}
    >
      {/* Card content */}
    </Card>
  );
}

Content Layout

Main Content

The card displays information in a structured layout:
<div className={s.content}>
  <div className={s.partnerName}>{order.partnerName}</div>
  
  <div className={s.orderNumber}>Orden: {order.displayNumber}</div>
  
  <span
    className={clsx(
      s.priority,
      isHighPriority ? s.priorityHigh : s.priorityNormal,
    )}
  >
    {isHighPriority ? "Alta" : "Normal"}
  </span>
  
  {order.activeTimer && (
    <div className={s.time}>
      <span className={s.clockIcon}>🕒</span>
      {formatHour(order.activeTimer)}
    </div>
  )}
</div>

Partner Name

Displays the restaurant or partner name at the top of the card.

Order Number

Shows the human-readable order display number prefixed with “Orden:”.

Priority Badge

// Displays "Alta" with high-priority styling
className={s.priorityHigh}
Used for urgent orders that need immediate attention.

Active Timer

Conditionally rendered when an order has an active timer:
{order.activeTimer && (
  <div className={s.time}>
    <span className={s.clockIcon}>🕒</span>
    {formatHour(order.activeTimer)}
  </div>
)}
The timer uses the formatHour helper to display elapsed time in a human-readable format (e.g., “12:34”).
When available, displays the partner’s logo:
{order.partnerImage && (
  <div className={s.logoWrapper}>
    <img
      src={order.partnerImage}
      alt={order.partnerName}
      loading="lazy"
    />
  </div>
)}
Images use lazy loading to improve initial page load performance.

Click Handling

The card implements click event handling with propagation control:
onClick={(e) => {
  e.stopPropagation();
  onClick?.();
}}
Why stopPropagation? The event propagation is stopped to prevent triggering parent drag-and-drop handlers when clicking the card. This allows:
  • Clicking to open order details
  • Dragging to move the order
These two interactions to coexist without conflict.

Priority Logic

const isHighPriority = order.priority === "HIGH";
The component determines priority treatment based on the order’s priority field. This affects:
  • Badge text (“Alta” vs “Normal”)
  • Badge styling (distinct colors)
  • Visual prominence in the UI

Usage Examples

Basic Usage

import OrderCard from "@/components/card/OrderCard";

function OrderList({ orders }) {
  return (
    <div>
      {orders.map((order) => (
        <OrderCard
          key={order.id}
          order={order}
          onClick={() => console.log('Order clicked:', order.id)}
        />
      ))}
    </div>
  );
}

As Drag Overlay

import { DragOverlay } from "@dnd-kit/core";
import OrderCard from "@/components/card/OrderCard";

function KanbanBoard() {
  const [activeOrder, setActiveOrder] = useState(null);
  
  return (
    <DragOverlay>
      {activeOrder && (
        <OrderCard
          order={activeOrder}
          isOverlay={true}
        />
      )}
    </DragOverlay>
  );
}

With Order Details Modal

import OrderCard from "@/components/card/OrderCard";
import { OrderDetailModal } from "@/components/modal/OrderDetailsModal";

function OrderColumn({ orders }) {
  const [selectedId, setSelectedId] = useState(null);
  
  return (
    <>
      {orders.map((order) => (
        <OrderCard
          key={order.id}
          order={order}
          onClick={() => setSelectedId(order.id)}
        />
      ))}
      
      {selectedId && (
        <OrderDetailModal
          orderId={selectedId}
          onClose={() => setSelectedId(null)}
        />
      )}
    </>
  );
}

Styling Considerations

The component uses CSS modules for scoped styling:
import s from "./OrderCard.module.scss";
Key style classes:
  • s.card: Base card styles
  • s.content: Content container layout
  • s.partnerName: Partner name typography
  • s.orderNumber: Order number display
  • s.priority: Priority badge base styles
  • s.priorityHigh: High priority badge styling
  • s.priorityNormal: Normal priority badge styling
  • s.time: Timer display container
  • s.clockIcon: Clock emoji styling
  • s.logoWrapper: Partner logo container
  • s.overlay: Special styling for drag overlay

Integration Points

Base Components

  • Card: Base card component providing elevation and sizing
  • clsx: Utility for conditional class composition

Helpers

  • formatHour: Formats timer values into human-readable time strings

Types

  • OrderListDto: Order data transfer object
  • OrderStatus: Enumeration of valid order statuses

Accessibility

Consider adding ARIA attributes for improved accessibility:
  • role="button" when onClick is provided
  • aria-label describing the order
  • tabIndex={0} for keyboard navigation
  • Kanban: Parent kanban board
  • Riders: Alternative card for picked-up orders
  • Column: Container for order cards (internal component)

Source Location

components/card/OrderCard.tsx:1

Build docs developers (and LLMs) love