channel / components / channel-message
ChannelMessageBubble
channel_messages record and draws the bubble: inbound on the left, outbound on the right, with the author, the platform badge, status and time in the header.Preview
Hola! Necesito cotizar 200 cascos certificados.
Tomo el pedido: 200 cascos IRAM 3620. ¿Fecha límite?
Install
pnpm dlx shadcn@latest add https://registry.ekairos.dev/r/channel-message.jsonStart simple: one inbound message
Hand it a message and it figures out the rest. direction decides the side, role decides the tone, and the badge tells the platform:
import { ChannelMessageBubble } from "@/components/ekairos/channel/channel-message";
<ChannelMessageBubble
message={{
id: "m1",
channel: "whatsapp",
direction: "inbound",
role: "user",
participant: "+54 9 11 5555-0147",
text: "Hola! Necesito cotizar 200 cascos certificados.",
createdAt: new Date().toISOString(),
}}
/>Then: across channels
The same component renders an email reply, a slack approval, an outbound RFQ — because it reads the canonical model, not provider payloads. And when your whole view is a single channel, pass hideChannel to drop the badge (the email below does exactly that):
Cotizamos USD 11.40/u, entrega 10 días hábiles.
Aprobado 👍 generá la OC.
Subject: RFQ — 200 cascos certificados Solicitamos cotización por 200 unidades.
What it actually renders
The body comes from the canonical content: text when present, otherwise it joins the parts with type: "text". The header line shows the author (participant, falling back to the role), the platform badge, the delivery status if any, and the local time from createdAt.
Props
| prop | type | description |
|---|---|---|
| message * | ChannelMessage | Canonical channel_messages record: channel, direction, role, participant, status, text or parts, createdAt. |
| hideChannel | boolean | Hide the channel badge (e.g. in single-channel views). |
| className | string | Extra classes for the bubble row. |