Design
llms.txt digitalcrew.tech

Pipeline

DealCard

One draggable deal on the deals board, plus DealCardPreview, the tilted copy shown under the cursor while dragging.

MaxPipelineDigitalCrew.DealCard
DealCard · liveOpen

Guidelines#

Use it for deal columns (see DealColumn). Render it inside a dnd-kit DndContext. It registers with useDraggable under id: deal.id and data: { type: "deal", deal, columnStageId }.

What you provide:

  • deal: DealWithRelationsDto: the deal row plus its organization and prospects.
  • columnStageId: the column the card is in.
  • onOpen(deal): called when the card is clicked.

DealCardPreview takes only deal.

Anatomy:

  • The body is bg-card rounded-lg border p-3 shadow-xs. The name is text-sm font-medium, truncated.
  • A metadata row follows (mt-1.5 text-xs text-muted-foreground, gap-x-3 gap-y-1, wrapping):
    • the amount in text-foreground font-medium, formatted by formatDealAmount (Intl currency, no decimals);
    • the contact with a 12px User icon: the primary contact, else the first one, shown as full name, then first + last name, then email;
    • the organization with Building2;
    • the close date with CalendarDays, formatted MMM d.
  • A deal with status won and no contact shows an amber "No contact" flag with TriangleAlert (text-amber-600 dark:text-amber-500). Its title tells the user to open the deal and link the person.

Behaviour: the card is cursor-grab touch-none. While it is dragged, the original goes to opacity 0 and the overlay carries it. DealCardPreview is w-[260px] rotate-2.

Don't format money yourself, and never add different currencies together.

Facts#

GroupPipeline
ProductMax
Globalwindow.DigitalCrew.DealCard
Sourcemax-agent: src/features/deals/ui/components/deal-card.tsx
Import in the appimport { DealCard } from "@/features/deals/ui/components/deal-card";

API#

TypeScript declarations emitted from src/features/deals/ui/components/deal-card.tsx (the module also exports DealCard, DealCardPreview).

export { formatCurrencySums, formatDealAmount } from "./deal-amount";
type DealCardProps = {
    deal: DealWithRelationsDto;
    columnStageId: string;
    onOpen: (deal: DealWithRelationsDto) => void;
};
export declare function DealCard({ deal, columnStageId, onOpen }: DealCardProps): JSX.Element;
/** Static clone rendered inside the DragOverlay. */
export declare function DealCardPreview({ deal }: {
    deal: DealWithRelationsDto;
}): JSX.Element;

Example#

The code of the preview above: plain React.createElement against window.DigitalCrew, with realistic data.

<div id="root" class="p-6"></div>
<script>
(function () {
  var h = React.createElement, DC = window.DigitalCrew, I = DC.Icons;
  var WS = "0b9f6c1e-3a52-4c1d-9e0a-5d2f7b8c4a10", PIPE = "5e1d2c3b-4a59-4f68-8a7b-6c5d4e3f2a1b";
  // DealWithRelationsDto: the deal row plus its organization and contacts.
  function deal(id, name, amount, currency, closeDate, status, org, contact) {
    return {
      id: id, workspace_id: WS, pipeline_id: PIPE, stage_id: "stage-" + status, name: name,
      amount: amount, currency: currency, close_date: closeDate, probability: null, status: status,
      won_at: status === "won" ? "2026-09-22T14:05:00Z" : null, lost_at: null, lost_reason: null,
      owner_id: null, organization_id: org ? org.id : null, description: null, custom_fields: null,
      source: "manual", created_by: null, created_at: "2026-08-30T09:00:00Z", updated_at: "2026-09-22T14:05:00Z",
      organization: org,
      prospects: contact ? [{
        deal_id: id, prospect_id: contact.id, workspace_id: WS, role: "Decision maker", is_primary: true,
        created_at: "2026-08-30T09:00:00Z",
        prospect: { id: contact.id, full_name: contact.name, first_name: null, last_name: null, email: null, title: contact.title, photo_url: null, organization_id: org ? org.id : null }
      }] : []
    };
  }
  var NORTHWIND = { id: "org-northwind", name: "Northwind Traders", primary_domain: "northwind.com" };
  var CONTOSO = { id: "org-contoso", name: "Contoso Logistics", primary_domain: "contoso.io" };
  var DEALS = [
    deal("d1", "Northwind Traders — DACH pilot", 48000, "EUR", "2026-10-15", "open", NORTHWIND, { id: "pr-1", name: "Claire Dubois", title: "CFO" }),
    deal("d2", "Contoso Logistics — annual plan", 96000, "EUR", "2026-09-22", "won", CONTOSO, null),
    deal("d3", "Fabrikam onboarding", null, "EUR", null, "open", null, { id: "pr-3", name: "Jonas Weber", title: "Head of Sales" })
  ];
  function App() {
    return h(DC.DndContext, null,
      h("div", { className: "flex flex-wrap items-start gap-8" },
        h("div", { className: "flex w-[280px] flex-col gap-2" },
          DEALS.map(function (d) {
            return h(DC.DealCard, { key: d.id, deal: d, columnStageId: d.stage_id, onOpen: function () {} });
          })),
        h("div", { className: "flex flex-col gap-3 pt-2" },
          h("p", { className: "text-xs font-medium text-muted-foreground" }, "While dragging (DealCardPreview)"),
          h(DC.DealCardPreview, { deal: DEALS[0] }))));
  }
  ReactDOM.createRoot(document.getElementById("root")).render(h(DC.TooltipProvider, { delayDuration: 80 }, h(App)));
})();
</script>