Skip to main content

Overview

The Riders component is a specialized card that displays courier (rider) information for orders in the “PICKED_UP” status. It shows rider details, order information, and a visual avatar, providing a distinct visual representation for orders currently with delivery couriers.
This component is used exclusively in the kanban board’s “PICKED_UP” column, replacing the standard OrderCard for better courier tracking.

Props Interface

type RidersProps = {
  rider: RiderDto;
  onClick?: () => void;
};
rider
RiderDto
required
The rider data object containing courier and order information.RiderDto Structure:
type RiderDto = {
  id: string;
  name: string;
  orderId: string;
  displayNumber: string;
  riderNumber: number;
  partnerName?: string;
}
onClick
() => void
Optional callback function invoked when the card is clicked. Typically used to open order details or rider information.

RiderDto Fields

Type: stringUnique identifier for the rider/order combination. Used as the React key and for lookups.

Component Structure

function Riders({ rider, onClick }: RidersProps) {
  return (
    <Card
      size="md"
      variant="elevated"
      className={clsx(s.riderCard)}
      onClick={(e) => {
        e.stopPropagation();
        onClick?.();
      }}
    >
      <div className={s.content}>
        <div className={s.info}>
          <div className={s.partner}>{rider.partnerName}</div>
          <div className={s.orderNumber}>Orden: {rider.displayNumber}</div>
          <div className={s.name}>{rider.name}</div>
          <div className={s.number}>Rider #{rider.riderNumber}</div>
        </div>

        <div className={s.avatar}>
          <RiderAvatar />
        </div>
      </div>
    </Card>
  );
}

Visual Layout

The component uses a two-column layout:

Left Column

Displays textual information:
  • Partner name (if available)
  • Order display number
  • Courier name
  • Rider number

Right Column

Shows a visual rider avatar for quick recognition

Information Display

Partner Name

<div className={s.partner}>{rider.partnerName}</div>
Displays the restaurant or partner name at the top. This helps identify which establishment the order is from.

Order Number

<div className={s.orderNumber}>Orden: {rider.displayNumber}</div>
Shows the order’s display number prefixed with “Orden:” for clarity. This matches the format used in OrderCard for consistency.

Rider Name

<div className={s.name}>{rider.name}</div>
Displays the courier’s name prominently. This is the primary identifier for tracking who has the order.

Rider Number

<div className={s.number}>Rider #{rider.riderNumber}</div>
Shows a numeric identifier for the rider in the format “Rider #123”. This provides an additional reference point for tracking and communication.

Click Handling

The component implements the same click handling pattern as OrderCard:
onClick={(e) => {
  e.stopPropagation();
  onClick?.();
}}
Event propagation is stopped to prevent conflicts with drag-and-drop handlers. This allows clicking to view order details while still supporting drag operations.

Memoization

The component is wrapped with React’s memo for performance optimization:
export default memo(Riders);
Benefits:
  • Prevents unnecessary re-renders when parent components update
  • Improves performance in lists with many rider cards
  • Only re-renders when props actually change
Because the component is memoized, ensure that the onClick callback is stable (e.g., wrapped in useCallback) to avoid breaking memoization.

Usage in Kanban

The Riders component is used in the Kanban board for picked-up orders:
{status === "PICKED_UP"
  ? riders.map((rider) => (
      <DraggableRiderCard
        key={rider.id}
        rider={rider}
        onClick={setSelectedOrderId}
      />
    ))
  : columnOrders.map((order) => (
      <DraggableOrderCard
        key={order.id}
        order={order}
        onClick={setSelectedOrderId}
      />
    ))}

Rider Data Transformation

Rider data is typically derived from orders with PICKED_UP status:
const riders: RiderDto[] = useMemo(() => {
  return Object.values(ordersByStatus)
    .flat()
    .filter((order) => order.status === "PICKED_UP" && order.courierName)
    .map(
      (order): RiderDto => ({
        id: order.id,
        name: order.courierName!,
        orderId: order.id,
        displayNumber: order.displayNumber,
        riderNumber: Number(order.id.slice(-3)) || 100,
        ...(order.partnerName && {
          partnerName: order.partnerName,
        }),
      }),
    );
}, [ordersByStatus]);

Usage Examples

Basic Usage

import Riders from "@/components/Riders/Riders";

function RiderList({ riders }) {
  return (
    <div>
      {riders.map((rider) => (
        <Riders
          key={rider.id}
          rider={rider}
          onClick={() => console.log('Rider clicked:', rider.id)}
        />
      ))}
    </div>
  );
}

With Order Details

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

function PickedUpColumn({ riders }) {
  const [selectedOrderId, setSelectedOrderId] = useState(null);
  
  return (
    <>
      {riders.map((rider) => (
        <Riders
          key={rider.id}
          rider={rider}
          onClick={() => setSelectedOrderId(rider.orderId)}
        />
      ))}
      
      {selectedOrderId && (
        <OrderDetailModal
          orderId={selectedOrderId}
          onClose={() => setSelectedOrderId(null)}
        />
      )}
    </>
  );
}

In Drag Overlay

import { DragOverlay } from "@dnd-kit/core";
import Riders from "@/components/Riders/Riders";
import { mapOrderToRiderViewModel } from "@/components/order/mappers/map-order-to-rider";

function KanbanBoard() {
  const [activeOrder, setActiveOrder] = useState(null);
  
  return (
    <DragOverlay>
      {activeOrder && activeOrder.status === "PICKED_UP" && (
        <Riders rider={mapOrderToRiderViewModel(activeOrder)} />
      )}
    </DragOverlay>
  );
}

Styling

The component uses CSS modules for scoped styling:
import s from "./Riders.module.scss";
Key style classes:
  • s.riderCard: Base card styling
  • s.content: Main content container
  • s.info: Information column layout
  • s.partner: Partner name styling
  • s.orderNumber: Order number display
  • s.name: Rider name typography
  • s.number: Rider number styling
  • s.avatar: Avatar container positioning

Integration Points

Base Components

  • Card: Provides the base card structure with elevation
  • RiderAvatar: Visual avatar representation of the courier
  • clsx: Utility for conditional class composition
  • RiderDto: Data transfer object for rider information
  • OrderListDto: Source order data (transformed to RiderDto)

Visual Differentiation

The Riders component provides several advantages over using OrderCard for picked-up orders:

Courier Focus

Emphasizes the courier rather than order status

Avatar Visual

Provides quick visual recognition with rider avatar

Rider Number

Includes rider-specific identification for tracking

Delivery Context

Better represents the delivery phase of the order lifecycle

Performance Considerations

  1. Memoization: Component is wrapped in memo() to prevent unnecessary re-renders
  2. Stable Props: Use stable callbacks (e.g., useCallback) for onClick to maintain memoization benefits
  3. Lazy Avatar: RiderAvatar component likely implements its own optimization

Accessibility Recommendations

Consider enhancing accessibility with:
  • role="button" when onClick is provided
  • aria-label describing the rider and order (e.g., “Rider Juan Pérez, Order 1234”)
  • tabIndex={0} for keyboard navigation
  • Focus indicators for keyboard users
  • Kanban: Parent component using Riders for picked-up orders
  • OrderCard: Alternative card for non-picked-up orders
  • DraggableRiderCard: Wrapper providing drag functionality (internal component)

Source Location

components/Riders/Riders.tsx:1

Build docs developers (and LLMs) love