myoperator-ui 0.0.222 → 0.0.223-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +319 -15
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -16577,6 +16577,306 @@ export interface ChatBubbleProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
16577
16577
|
name: "index.ts",
|
|
16578
16578
|
content: prefixTailwindClasses(`export { ChatBubble } from "./chat-bubble";
|
|
16579
16579
|
export type { ChatBubbleProps, ChatBubbleReply, DeliveryStatus } from "./types";
|
|
16580
|
+
`, prefix)
|
|
16581
|
+
}
|
|
16582
|
+
]
|
|
16583
|
+
},
|
|
16584
|
+
"chat-list-item": {
|
|
16585
|
+
name: "chat-list-item",
|
|
16586
|
+
description: "A chat list item showing contact name, message preview, timestamp, delivery status, and channel badge",
|
|
16587
|
+
category: "custom",
|
|
16588
|
+
dependencies: [
|
|
16589
|
+
"clsx",
|
|
16590
|
+
"tailwind-merge",
|
|
16591
|
+
"lucide-react"
|
|
16592
|
+
],
|
|
16593
|
+
internalDependencies: [],
|
|
16594
|
+
isMultiFile: true,
|
|
16595
|
+
directory: "chat-list-item",
|
|
16596
|
+
mainFile: "chat-list-item.tsx",
|
|
16597
|
+
files: [
|
|
16598
|
+
{
|
|
16599
|
+
name: "chat-list-item.tsx",
|
|
16600
|
+
content: prefixTailwindClasses(`import * as React from "react";
|
|
16601
|
+
import { cn } from "../../../lib/utils";
|
|
16602
|
+
import {
|
|
16603
|
+
Bot,
|
|
16604
|
+
Check,
|
|
16605
|
+
CheckCheck,
|
|
16606
|
+
Clock,
|
|
16607
|
+
FileText,
|
|
16608
|
+
Image as ImageIcon,
|
|
16609
|
+
} from "lucide-react";
|
|
16610
|
+
|
|
16611
|
+
/* \u2500\u2500 Types \u2500\u2500 */
|
|
16612
|
+
|
|
16613
|
+
export type MessageStatus = "sent" | "delivered" | "read";
|
|
16614
|
+
|
|
16615
|
+
export type MessageType = "text" | "document" | "image";
|
|
16616
|
+
|
|
16617
|
+
export interface ChatListItemProps
|
|
16618
|
+
extends Omit<React.HTMLAttributes<HTMLDivElement>, "onClick"> {
|
|
16619
|
+
/** Contact or customer name (supports ReactNode for highlighted search matches) */
|
|
16620
|
+
name: React.ReactNode;
|
|
16621
|
+
/** Last message preview text (supports ReactNode for highlighted search matches) */
|
|
16622
|
+
message: React.ReactNode;
|
|
16623
|
+
/** Timestamp display string (e.g. "2:30 PM", "Yesterday") */
|
|
16624
|
+
timestamp: string;
|
|
16625
|
+
/**
|
|
16626
|
+
* Delivery status of the last outbound message.
|
|
16627
|
+
* Mutually exclusive with \`unreadCount\` \u2014 when set, no unread badge is shown.
|
|
16628
|
+
* - \`sent\`: single gray checkmark (message left the server)
|
|
16629
|
+
* - \`delivered\`: double gray checkmarks (reached the customer's device)
|
|
16630
|
+
* - \`read\`: double blue checkmarks (customer opened the message)
|
|
16631
|
+
*/
|
|
16632
|
+
messageStatus?: MessageStatus;
|
|
16633
|
+
/**
|
|
16634
|
+
* Number of unread messages from the customer.
|
|
16635
|
+
* Only shown when \`messageStatus\` is not set (i.e., last message was inbound).
|
|
16636
|
+
*/
|
|
16637
|
+
unreadCount?: number;
|
|
16638
|
+
/**
|
|
16639
|
+
* SLA timer label showing how long the customer has been waiting (e.g. "2h", "50m").
|
|
16640
|
+
* Displayed as a warning-colored tag next to the name.
|
|
16641
|
+
* Typically appears on unread/inbound conversations.
|
|
16642
|
+
*/
|
|
16643
|
+
slaTimer?: string;
|
|
16644
|
+
/**
|
|
16645
|
+
* Type of the last message \u2014 controls the icon prefix before the message text.
|
|
16646
|
+
* - \`text\`: no icon (default)
|
|
16647
|
+
* - \`document\`: file icon
|
|
16648
|
+
* - \`image\`: image icon
|
|
16649
|
+
*/
|
|
16650
|
+
messageType?: MessageType;
|
|
16651
|
+
/** Channel identifier (e.g. "MY01") */
|
|
16652
|
+
channel: string;
|
|
16653
|
+
/** Name of the assigned agent */
|
|
16654
|
+
agentName?: string;
|
|
16655
|
+
/** Whether the assigned agent's account has been deleted \u2014 renders in error color */
|
|
16656
|
+
isAgentDeleted?: boolean;
|
|
16657
|
+
/** Whether the conversation is handled by an AI/IVR bot \u2014 shows bot icon */
|
|
16658
|
+
isBot?: boolean;
|
|
16659
|
+
/** Whether this item is currently selected/active in the inbox */
|
|
16660
|
+
isSelected?: boolean;
|
|
16661
|
+
/** Callback when the chat item is clicked */
|
|
16662
|
+
onClick?: (event: React.MouseEvent<HTMLDivElement>) => void;
|
|
16663
|
+
}
|
|
16664
|
+
|
|
16665
|
+
/* \u2500\u2500 Sub-components \u2500\u2500 */
|
|
16666
|
+
|
|
16667
|
+
function StatusIndicator({ status }: { status: MessageStatus }) {
|
|
16668
|
+
if (status === "sent") {
|
|
16669
|
+
return (
|
|
16670
|
+
<span aria-label="Sent">
|
|
16671
|
+
<Check className="size-4 text-semantic-text-placeholder shrink-0" aria-hidden="true" />
|
|
16672
|
+
</span>
|
|
16673
|
+
);
|
|
16674
|
+
}
|
|
16675
|
+
if (status === "delivered") {
|
|
16676
|
+
return (
|
|
16677
|
+
<span aria-label="Delivered">
|
|
16678
|
+
<CheckCheck className="size-4 text-semantic-text-placeholder shrink-0" aria-hidden="true" />
|
|
16679
|
+
</span>
|
|
16680
|
+
);
|
|
16681
|
+
}
|
|
16682
|
+
// read
|
|
16683
|
+
return (
|
|
16684
|
+
<span aria-label="Read">
|
|
16685
|
+
<CheckCheck className="size-4 text-[#47b5bc] shrink-0" aria-hidden="true" />
|
|
16686
|
+
</span>
|
|
16687
|
+
);
|
|
16688
|
+
}
|
|
16689
|
+
|
|
16690
|
+
function UnreadBadge({ count }: { count: number }) {
|
|
16691
|
+
return (
|
|
16692
|
+
<span
|
|
16693
|
+
className="shrink-0 inline-flex items-center justify-center rounded-full bg-semantic-border-accent font-semibold text-white"
|
|
16694
|
+
style={{ width: 18, height: 18, fontSize: 10, lineHeight: 1 }}
|
|
16695
|
+
aria-label={\`\${count > 99 ? "99+" : count} unread messages\`}
|
|
16696
|
+
>
|
|
16697
|
+
{count > 99 ? "99+" : count}
|
|
16698
|
+
</span>
|
|
16699
|
+
);
|
|
16700
|
+
}
|
|
16701
|
+
|
|
16702
|
+
function SlaTag({ timer }: { timer: string }) {
|
|
16703
|
+
return (
|
|
16704
|
+
<span
|
|
16705
|
+
className="flex items-center gap-2 h-5 px-[6px] py-[2px] rounded bg-semantic-warning-surface shrink-0"
|
|
16706
|
+
aria-label={\`SLA timer: \${timer}\`}
|
|
16707
|
+
>
|
|
16708
|
+
<Clock className="size-3 text-semantic-warning-text" aria-hidden="true" />
|
|
16709
|
+
<span className="text-[12px] text-semantic-warning-text">{timer}</span>
|
|
16710
|
+
</span>
|
|
16711
|
+
);
|
|
16712
|
+
}
|
|
16713
|
+
|
|
16714
|
+
function MessageTypeIcon({ type }: { type: MessageType }) {
|
|
16715
|
+
if (type === "document") {
|
|
16716
|
+
return <FileText className="size-[14px] text-semantic-text-placeholder shrink-0" />;
|
|
16717
|
+
}
|
|
16718
|
+
if (type === "image") {
|
|
16719
|
+
return <ImageIcon className="size-[14px] text-semantic-text-placeholder shrink-0" />;
|
|
16720
|
+
}
|
|
16721
|
+
return null;
|
|
16722
|
+
}
|
|
16723
|
+
|
|
16724
|
+
function ChannelPill({
|
|
16725
|
+
channel,
|
|
16726
|
+
agentName,
|
|
16727
|
+
isAgentDeleted,
|
|
16728
|
+
isBot,
|
|
16729
|
+
}: {
|
|
16730
|
+
channel: string;
|
|
16731
|
+
agentName?: string;
|
|
16732
|
+
isAgentDeleted?: boolean;
|
|
16733
|
+
isBot?: boolean;
|
|
16734
|
+
}) {
|
|
16735
|
+
const textColor = isAgentDeleted ? "text-semantic-error-text" : "text-semantic-text-primary";
|
|
16736
|
+
|
|
16737
|
+
return (
|
|
16738
|
+
<div className="flex items-center gap-3">
|
|
16739
|
+
<span
|
|
16740
|
+
className={cn(
|
|
16741
|
+
"inline-flex items-center gap-[6px] px-2 py-1 rounded-[12px] border border-solid border-semantic-border-layout text-[12px]",
|
|
16742
|
+
textColor
|
|
16743
|
+
)}
|
|
16744
|
+
>
|
|
16745
|
+
{channel}
|
|
16746
|
+
{agentName && (
|
|
16747
|
+
<>
|
|
16748
|
+
<span>-</span>
|
|
16749
|
+
<span className="truncate">{agentName}</span>
|
|
16750
|
+
</>
|
|
16751
|
+
)}
|
|
16752
|
+
{isBot && <Bot className="size-[14px] text-semantic-text-primary" aria-hidden="true" />}
|
|
16753
|
+
</span>
|
|
16754
|
+
</div>
|
|
16755
|
+
);
|
|
16756
|
+
}
|
|
16757
|
+
|
|
16758
|
+
/* \u2500\u2500 Main Component \u2500\u2500 */
|
|
16759
|
+
|
|
16760
|
+
/**
|
|
16761
|
+
* ChatListItem displays a conversation preview in an inbox-style list.
|
|
16762
|
+
*
|
|
16763
|
+
* Each item shows the contact name, last message preview, timestamp,
|
|
16764
|
+
* delivery status or unread count, optional SLA timer, and channel/agent info.
|
|
16765
|
+
*
|
|
16766
|
+
* @example
|
|
16767
|
+
* \`\`\`tsx
|
|
16768
|
+
* <ChatListItem
|
|
16769
|
+
* name="Aditi Kumar"
|
|
16770
|
+
* message="Have a look at this document"
|
|
16771
|
+
* timestamp="2:30 PM"
|
|
16772
|
+
* messageStatus="sent"
|
|
16773
|
+
* messageType="document"
|
|
16774
|
+
* channel="MY01"
|
|
16775
|
+
* agentName="Alex Smith"
|
|
16776
|
+
* onClick={() => setSelectedChat("1")}
|
|
16777
|
+
* />
|
|
16778
|
+
* \`\`\`
|
|
16779
|
+
*/
|
|
16780
|
+
const ChatListItem = React.forwardRef(
|
|
16781
|
+
(
|
|
16782
|
+
{
|
|
16783
|
+
name,
|
|
16784
|
+
message,
|
|
16785
|
+
timestamp,
|
|
16786
|
+
messageStatus,
|
|
16787
|
+
unreadCount,
|
|
16788
|
+
slaTimer,
|
|
16789
|
+
messageType = "text",
|
|
16790
|
+
channel,
|
|
16791
|
+
agentName,
|
|
16792
|
+
isAgentDeleted = false,
|
|
16793
|
+
isBot = false,
|
|
16794
|
+
isSelected = false,
|
|
16795
|
+
onClick,
|
|
16796
|
+
className,
|
|
16797
|
+
...props
|
|
16798
|
+
}: ChatListItemProps,
|
|
16799
|
+
ref: React.Ref<HTMLDivElement>
|
|
16800
|
+
) => {
|
|
16801
|
+
const nameText = typeof name === "string" ? name : "";
|
|
16802
|
+
const messageText = typeof message === "string" ? message : "";
|
|
16803
|
+
const defaultAriaLabel = \`\${nameText}. \${messageText}. \${timestamp}\${unreadCount ? \`. \${unreadCount} unread\` : ""}\${slaTimer ? \`. SLA: \${slaTimer}\` : ""}\${messageStatus ? \`. \${messageStatus}\` : ""}\`;
|
|
16804
|
+
|
|
16805
|
+
return (
|
|
16806
|
+
<div
|
|
16807
|
+
ref={ref}
|
|
16808
|
+
role="button"
|
|
16809
|
+
tabIndex={0}
|
|
16810
|
+
aria-selected={isSelected}
|
|
16811
|
+
aria-label={defaultAriaLabel}
|
|
16812
|
+
onClick={onClick}
|
|
16813
|
+
onKeyDown={(e) => {
|
|
16814
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
16815
|
+
e.preventDefault();
|
|
16816
|
+
onClick?.(e as unknown as React.MouseEvent<HTMLDivElement>);
|
|
16817
|
+
}
|
|
16818
|
+
}}
|
|
16819
|
+
className={cn(
|
|
16820
|
+
"flex items-start px-4 py-5 w-full transition-colors cursor-pointer",
|
|
16821
|
+
isSelected
|
|
16822
|
+
? "bg-[var(--color-neutral-50)] border-l-4 border-solid border-l-semantic-border-accent border-b border-b-semantic-border-layout"
|
|
16823
|
+
: "bg-white hover:bg-[var(--color-neutral-50)] border-b border-solid border-semantic-border-layout",
|
|
16824
|
+
className
|
|
16825
|
+
)}
|
|
16826
|
+
{...props}
|
|
16827
|
+
>
|
|
16828
|
+
<div className="flex flex-col gap-2 flex-1 min-w-0">
|
|
16829
|
+
{/* Row 1: Name + SLA Timer + Status/Unread Badge */}
|
|
16830
|
+
<div className="flex items-center gap-[6px]">
|
|
16831
|
+
<div className="flex items-center gap-3 flex-1 min-w-0">
|
|
16832
|
+
<span className="text-[14px] text-semantic-text-primary truncate">
|
|
16833
|
+
{name}
|
|
16834
|
+
</span>
|
|
16835
|
+
{slaTimer && <SlaTag timer={slaTimer} />}
|
|
16836
|
+
</div>
|
|
16837
|
+
{messageStatus ? (
|
|
16838
|
+
<StatusIndicator status={messageStatus} />
|
|
16839
|
+
) : unreadCount ? (
|
|
16840
|
+
<UnreadBadge count={unreadCount} />
|
|
16841
|
+
) : null}
|
|
16842
|
+
</div>
|
|
16843
|
+
|
|
16844
|
+
{/* Row 2: Message Type Icon + Message Preview + Timestamp */}
|
|
16845
|
+
<div className="flex items-center gap-[6px]">
|
|
16846
|
+
<MessageTypeIcon type={messageType} />
|
|
16847
|
+
<p className="flex-1 text-[14px] text-semantic-text-muted truncate min-w-0 m-0">
|
|
16848
|
+
{message}
|
|
16849
|
+
</p>
|
|
16850
|
+
<span className="text-[12px] text-semantic-text-placeholder tracking-[0.06px] shrink-0">
|
|
16851
|
+
{timestamp}
|
|
16852
|
+
</span>
|
|
16853
|
+
</div>
|
|
16854
|
+
|
|
16855
|
+
{/* Row 3: Channel + Agent Pill */}
|
|
16856
|
+
<ChannelPill
|
|
16857
|
+
channel={channel}
|
|
16858
|
+
agentName={agentName}
|
|
16859
|
+
isAgentDeleted={isAgentDeleted}
|
|
16860
|
+
isBot={isBot}
|
|
16861
|
+
/>
|
|
16862
|
+
</div>
|
|
16863
|
+
</div>
|
|
16864
|
+
);
|
|
16865
|
+
}
|
|
16866
|
+
);
|
|
16867
|
+
ChatListItem.displayName = "ChatListItem";
|
|
16868
|
+
|
|
16869
|
+
export { ChatListItem };
|
|
16870
|
+
`, prefix)
|
|
16871
|
+
},
|
|
16872
|
+
{
|
|
16873
|
+
name: "index.ts",
|
|
16874
|
+
content: prefixTailwindClasses(`export { ChatListItem } from "./chat-list-item";
|
|
16875
|
+
export type {
|
|
16876
|
+
ChatListItemProps,
|
|
16877
|
+
MessageStatus,
|
|
16878
|
+
MessageType,
|
|
16879
|
+
} from "./chat-list-item";
|
|
16580
16880
|
`, prefix)
|
|
16581
16881
|
}
|
|
16582
16882
|
]
|
|
@@ -23518,12 +23818,12 @@ export type { ChatContextValue } from "./types"
|
|
|
23518
23818
|
{
|
|
23519
23819
|
name: "chat-sidebar.tsx",
|
|
23520
23820
|
content: prefixTailwindClasses(`import * as React from "react"
|
|
23521
|
-
import { cn } from "
|
|
23821
|
+
import { cn } from "../../../../lib/utils"
|
|
23522
23822
|
import { Button } from "../../button"
|
|
23523
23823
|
import { TextField } from "../../text-field"
|
|
23524
23824
|
import { Tabs, TabsList, TabsTrigger } from "../../tabs"
|
|
23525
23825
|
import { Badge } from "../../badge"
|
|
23526
|
-
import { ChatListItem, type MessageType } from "
|
|
23826
|
+
import { ChatListItem, type MessageType } from "../../chat-list-item"
|
|
23527
23827
|
import { useChatContext } from "../chat-provider"
|
|
23528
23828
|
import type { Tab } from "../chat-types"
|
|
23529
23829
|
import { Search, Plus, CircleAlert } from "lucide-react"
|
|
@@ -23846,11 +24146,15 @@ export function ChatFilterPanel({ onClose, onApply }: ChatFilterPanelProps) {
|
|
|
23846
24146
|
const isDirty = () => {
|
|
23847
24147
|
if (selectedAssignees.size !== initialAssignees.current.size) return true
|
|
23848
24148
|
if (selectedChannels.size !== initialChannels.current.size) return true
|
|
23849
|
-
|
|
23850
|
-
|
|
23851
|
-
|
|
23852
|
-
|
|
23853
|
-
return
|
|
24149
|
+
let dirty = false
|
|
24150
|
+
selectedAssignees.forEach((id) => {
|
|
24151
|
+
if (!initialAssignees.current.has(id)) dirty = true
|
|
24152
|
+
})
|
|
24153
|
+
if (dirty) return true
|
|
24154
|
+
selectedChannels.forEach((id) => {
|
|
24155
|
+
if (!initialChannels.current.has(id)) dirty = true
|
|
24156
|
+
})
|
|
24157
|
+
return dirty
|
|
23854
24158
|
}
|
|
23855
24159
|
|
|
23856
24160
|
const handleBack = () => {
|
|
@@ -24231,7 +24535,7 @@ export type { ChatFilterPanelProps } from "./chat-filter-panel"
|
|
|
24231
24535
|
{
|
|
24232
24536
|
name: "chat-new-panel.tsx",
|
|
24233
24537
|
content: prefixTailwindClasses(`import * as React from "react"
|
|
24234
|
-
import { cn } from "
|
|
24538
|
+
import { cn } from "../../../../lib/utils"
|
|
24235
24539
|
import { Button } from "../../button"
|
|
24236
24540
|
import { TextField } from "../../text-field"
|
|
24237
24541
|
import {
|
|
@@ -24392,7 +24696,7 @@ export { ChatNewPanel }
|
|
|
24392
24696
|
{
|
|
24393
24697
|
name: "add-contact-modal.tsx",
|
|
24394
24698
|
content: prefixTailwindClasses(`import * as React from "react"
|
|
24395
|
-
import { cn } from "
|
|
24699
|
+
import { cn } from "../../../../lib/utils"
|
|
24396
24700
|
import { Button } from "../../button"
|
|
24397
24701
|
import { TextField } from "../../text-field"
|
|
24398
24702
|
import {
|
|
@@ -24933,7 +25237,7 @@ export {
|
|
|
24933
25237
|
{
|
|
24934
25238
|
name: "chat-message-list.tsx",
|
|
24935
25239
|
content: prefixTailwindClasses(`import * as React from "react"
|
|
24936
|
-
import { cn } from "
|
|
25240
|
+
import { cn } from "../../../../lib/utils"
|
|
24937
25241
|
import { Button } from "../../button"
|
|
24938
25242
|
import {
|
|
24939
25243
|
Tooltip,
|
|
@@ -24949,8 +25253,8 @@ import {
|
|
|
24949
25253
|
File,
|
|
24950
25254
|
ArrowDown,
|
|
24951
25255
|
} from "lucide-react"
|
|
24952
|
-
import { ChatTimelineDivider } from "
|
|
24953
|
-
import { DocMedia } from "
|
|
25256
|
+
import { ChatTimelineDivider } from "../../chat-timeline-divider"
|
|
25257
|
+
import { DocMedia } from "../../doc-media"
|
|
24954
25258
|
import { useChatContext } from "../chat-provider"
|
|
24955
25259
|
import type { ChatMessage } from "../chat-types"
|
|
24956
25260
|
import {
|
|
@@ -25566,7 +25870,7 @@ export { AssignmentDropdown }
|
|
|
25566
25870
|
name: "resolve-button.tsx",
|
|
25567
25871
|
content: prefixTailwindClasses(`import { useState } from "react"
|
|
25568
25872
|
import { Check } from "lucide-react"
|
|
25569
|
-
import { cn } from "
|
|
25873
|
+
import { cn } from "../../../../lib/utils"
|
|
25570
25874
|
import { Button } from "../../button"
|
|
25571
25875
|
import { useChatContext } from "../chat-provider"
|
|
25572
25876
|
|
|
@@ -25930,7 +26234,7 @@ import {
|
|
|
25930
26234
|
TooltipTrigger,
|
|
25931
26235
|
TooltipArrow,
|
|
25932
26236
|
} from "../../tooltip"
|
|
25933
|
-
import { ChatComposer } from "
|
|
26237
|
+
import { ChatComposer } from "../../chat-composer"
|
|
25934
26238
|
import { ComposerAttachmentPreview } from "./composer-attachment-preview"
|
|
25935
26239
|
import { CannedMessagesDropdown } from "./canned-messages"
|
|
25936
26240
|
import { useChatContext } from "../chat-provider"
|
|
@@ -27597,7 +27901,7 @@ export function resolveVars(
|
|
|
27597
27901
|
{
|
|
27598
27902
|
name: "chat-app.tsx",
|
|
27599
27903
|
content: prefixTailwindClasses(`import * as React from "react"
|
|
27600
|
-
import { cn } from "
|
|
27904
|
+
import { cn } from "../../../../lib/utils"
|
|
27601
27905
|
import { Button } from "../../button"
|
|
27602
27906
|
import {
|
|
27603
27907
|
TooltipProvider,
|