@algenium/blocks 1.16.1 → 1.18.0

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.cjs CHANGED
@@ -6737,7 +6737,9 @@ function ChatSidebarProvider({
6737
6737
  const [isLoading, setIsLoading] = React7.useState(false);
6738
6738
  const [activeCaseId, setActiveCaseId] = React7.useState(null);
6739
6739
  const [activeRoomId, setActiveRoomId] = React7.useState(null);
6740
+ const [searchQuery, setSearchQuery] = React7.useState("");
6740
6741
  const fetchRef = React7.useRef(fetchConversations);
6742
+ const prevOpenRef = React7.useRef(isOpen);
6741
6743
  fetchRef.current = fetchConversations;
6742
6744
  const persistOpen = React7.useCallback((open2) => {
6743
6745
  setIsOpen(open2);
@@ -6759,6 +6761,32 @@ function ChatSidebarProvider({
6759
6761
  React7.useEffect(() => {
6760
6762
  void loadConversations();
6761
6763
  }, [loadConversations]);
6764
+ React7.useEffect(() => {
6765
+ if (isOpen && !prevOpenRef.current) {
6766
+ void loadConversations();
6767
+ }
6768
+ prevOpenRef.current = isOpen;
6769
+ }, [isOpen, loadConversations]);
6770
+ const clearRoomUnread = React7.useCallback((roomId) => {
6771
+ setConversations(
6772
+ (prev) => prev.map((conv) => ({
6773
+ ...conv,
6774
+ rooms: conv.rooms.map(
6775
+ (room) => room.id === roomId ? { ...room, unreadCount: 0 } : room
6776
+ )
6777
+ }))
6778
+ );
6779
+ }, []);
6780
+ const totalUnreadCount = React7.useMemo(
6781
+ () => conversations.reduce(
6782
+ (sum, conv) => sum + conv.rooms.reduce(
6783
+ (roomSum, room) => roomSum + (room.unreadCount ?? 0),
6784
+ 0
6785
+ ),
6786
+ 0
6787
+ ),
6788
+ [conversations]
6789
+ );
6762
6790
  const toggle = React7.useCallback(() => persistOpen(!isOpen), [isOpen, persistOpen]);
6763
6791
  const open = React7.useCallback(() => persistOpen(true), [persistOpen]);
6764
6792
  const close = React7.useCallback(() => {
@@ -6766,6 +6794,7 @@ function ChatSidebarProvider({
6766
6794
  setView("list");
6767
6795
  setActiveCaseId(null);
6768
6796
  setActiveRoomId(null);
6797
+ setSearchQuery("");
6769
6798
  }, [persistOpen]);
6770
6799
  const openChat = React7.useCallback(
6771
6800
  (caseId, roomId) => {
@@ -6807,31 +6836,40 @@ function ChatSidebarProvider({
6807
6836
  isLoading,
6808
6837
  activeCaseId,
6809
6838
  activeRoomId,
6839
+ searchQuery,
6840
+ setSearchQuery,
6841
+ totalUnreadCount,
6810
6842
  toggle,
6811
6843
  open,
6812
6844
  close,
6813
6845
  openChat,
6814
6846
  selectRoom,
6815
6847
  back,
6816
- refetch: loadConversations
6848
+ refetch: loadConversations,
6849
+ clearRoomUnread
6817
6850
  };
6818
6851
  return /* @__PURE__ */ jsxRuntime.jsx(ChatSidebarContext.Provider, { value, children });
6819
6852
  }
6820
6853
  var PING_INTERVAL = 3e4;
6821
6854
  var MIN_RECONNECT_DELAY = 1e3;
6822
6855
  var MAX_RECONNECT_DELAY = 3e4;
6856
+ var MARK_READ_DEBOUNCE_MS = 1e3;
6823
6857
  function useChatRoom(roomId, config, options = {}) {
6824
6858
  const {
6825
6859
  minReconnectDelay = MIN_RECONNECT_DELAY,
6826
6860
  maxReconnectDelay = MAX_RECONNECT_DELAY,
6827
- pingInterval = PING_INTERVAL
6861
+ pingInterval = PING_INTERVAL,
6862
+ onMarkedRead
6828
6863
  } = options;
6829
6864
  const [messages, setMessages] = React7.useState([]);
6830
6865
  const [isConnected, setIsConnected] = React7.useState(false);
6831
6866
  const [error, setError] = React7.useState(null);
6832
6867
  const [typingUsers, setTypingUsers] = React7.useState([]);
6868
+ const [onlineUserIds, setOnlineUserIds] = React7.useState([]);
6869
+ const [readReceipts, setReadReceipts] = React7.useState({});
6833
6870
  const [hasMoreHistory, setHasMoreHistory] = React7.useState(true);
6834
6871
  const [isLoadingHistory, setIsLoadingHistory] = React7.useState(false);
6872
+ const [isInitialLoading, setIsInitialLoading] = React7.useState(false);
6835
6873
  const wsRef = React7.useRef(null);
6836
6874
  const mountedRef = React7.useRef(true);
6837
6875
  const reconnectDelayRef = React7.useRef(minReconnectDelay);
@@ -6844,8 +6882,13 @@ function useChatRoom(roomId, config, options = {}) {
6844
6882
  () => Promise.resolve()
6845
6883
  );
6846
6884
  const configRef = React7.useRef(config);
6885
+ const onMarkedReadRef = React7.useRef(onMarkedRead);
6886
+ const lastSentWatermarkRef = React7.useRef(null);
6887
+ const pendingMarkRef = React7.useRef(null);
6888
+ const markReadTimerRef = React7.useRef(null);
6847
6889
  roomIdRef.current = roomId;
6848
6890
  configRef.current = config;
6891
+ onMarkedReadRef.current = onMarkedRead;
6849
6892
  const clearTimers = React7.useCallback(() => {
6850
6893
  if (reconnectTimerRef.current) {
6851
6894
  clearTimeout(reconnectTimerRef.current);
@@ -6855,7 +6898,74 @@ function useChatRoom(roomId, config, options = {}) {
6855
6898
  clearInterval(pingTimerRef.current);
6856
6899
  pingTimerRef.current = null;
6857
6900
  }
6901
+ if (markReadTimerRef.current) {
6902
+ clearTimeout(markReadTimerRef.current);
6903
+ markReadTimerRef.current = null;
6904
+ }
6905
+ }, []);
6906
+ const flushMarkRead = React7.useCallback(async () => {
6907
+ const pending = pendingMarkRef.current;
6908
+ const currentRoomId = roomIdRef.current;
6909
+ if (!pending || !currentRoomId) return;
6910
+ const { lastMessageId, lastReadAt } = pending;
6911
+ pendingMarkRef.current = null;
6912
+ if (lastSentWatermarkRef.current && lastSentWatermarkRef.current >= lastReadAt) {
6913
+ return;
6914
+ }
6915
+ const ws = wsRef.current;
6916
+ if (ws && ws.readyState === WebSocket.OPEN) {
6917
+ ws.send(
6918
+ JSON.stringify({
6919
+ type: "mark_read",
6920
+ lastMessageId,
6921
+ lastReadAt
6922
+ })
6923
+ );
6924
+ lastSentWatermarkRef.current = lastReadAt;
6925
+ onMarkedReadRef.current?.(currentRoomId);
6926
+ return;
6927
+ }
6928
+ try {
6929
+ const jwt = await configRef.current.getToken();
6930
+ if (!jwt) return;
6931
+ const res = await fetch(
6932
+ `${configRef.current.baseUrl}/rooms/${currentRoomId}/read`,
6933
+ {
6934
+ method: "POST",
6935
+ headers: {
6936
+ Authorization: `Bearer ${jwt}`,
6937
+ "Content-Type": "application/json"
6938
+ },
6939
+ body: JSON.stringify({ lastMessageId, lastReadAt })
6940
+ }
6941
+ );
6942
+ if (res.ok) {
6943
+ lastSentWatermarkRef.current = lastReadAt;
6944
+ onMarkedReadRef.current?.(currentRoomId);
6945
+ }
6946
+ } catch {
6947
+ }
6858
6948
  }, []);
6949
+ const markRead = React7.useCallback(
6950
+ (lastMessageId, lastReadAt) => {
6951
+ if (lastSentWatermarkRef.current && lastSentWatermarkRef.current >= lastReadAt) {
6952
+ return;
6953
+ }
6954
+ const pending = pendingMarkRef.current;
6955
+ if (pending && pending.lastReadAt >= lastReadAt) {
6956
+ return;
6957
+ }
6958
+ pendingMarkRef.current = { lastMessageId, lastReadAt };
6959
+ if (markReadTimerRef.current) {
6960
+ clearTimeout(markReadTimerRef.current);
6961
+ }
6962
+ markReadTimerRef.current = setTimeout(() => {
6963
+ markReadTimerRef.current = null;
6964
+ void flushMarkRead();
6965
+ }, MARK_READ_DEBOUNCE_MS);
6966
+ },
6967
+ [flushMarkRead]
6968
+ );
6859
6969
  const loadMoreHistory = React7.useCallback(async () => {
6860
6970
  if (!roomIdRef.current || isLoadingHistory || !hasMoreHistory) return;
6861
6971
  setIsLoadingHistory(true);
@@ -6888,6 +6998,7 @@ function useChatRoom(roomId, config, options = {}) {
6888
6998
  } catch {
6889
6999
  } finally {
6890
7000
  setIsLoadingHistory(false);
7001
+ setIsInitialLoading(false);
6891
7002
  }
6892
7003
  }, [isLoadingHistory, hasMoreHistory]);
6893
7004
  const sendMessage = React7.useCallback(
@@ -6921,6 +7032,7 @@ function useChatRoom(roomId, config, options = {}) {
6921
7032
  } catch {
6922
7033
  if (mountedRef.current) {
6923
7034
  setError("Failed to get authentication token");
7035
+ setIsInitialLoading(false);
6924
7036
  }
6925
7037
  return;
6926
7038
  }
@@ -6936,6 +7048,7 @@ function useChatRoom(roomId, config, options = {}) {
6936
7048
  setError(
6937
7049
  err instanceof Error ? err.message : "WebSocket creation failed"
6938
7050
  );
7051
+ setIsInitialLoading(false);
6939
7052
  }
6940
7053
  return;
6941
7054
  }
@@ -6960,9 +7073,23 @@ function useChatRoom(roomId, config, options = {}) {
6960
7073
  try {
6961
7074
  const msg = JSON.parse(event.data);
6962
7075
  switch (msg.type) {
6963
- case "server_hello":
7076
+ case "server_hello": {
7077
+ const readState = msg.readState;
7078
+ if (readState) {
7079
+ setReadReceipts((prev) => {
7080
+ const next = { ...prev };
7081
+ for (const entry of readState) {
7082
+ const existing = next[entry.userId];
7083
+ if (!existing || existing < entry.lastReadAt) {
7084
+ next[entry.userId] = entry.lastReadAt;
7085
+ }
7086
+ }
7087
+ return next;
7088
+ });
7089
+ }
6964
7090
  void loadMoreHistoryRef.current();
6965
7091
  break;
7092
+ }
6966
7093
  case "new_message": {
6967
7094
  const message = msg.message;
6968
7095
  if (!messageIdsRef.current.has(message.id)) {
@@ -6987,6 +7114,25 @@ function useChatRoom(roomId, config, options = {}) {
6987
7114
  });
6988
7115
  break;
6989
7116
  }
7117
+ case "presence_update": {
7118
+ const ids = msg.onlineUserIds;
7119
+ if (Array.isArray(ids)) {
7120
+ setOnlineUserIds(ids);
7121
+ }
7122
+ break;
7123
+ }
7124
+ case "read_receipt": {
7125
+ const userId = msg.userId;
7126
+ const lastReadAt = msg.lastReadAt;
7127
+ if (userId && lastReadAt) {
7128
+ setReadReceipts((prev) => {
7129
+ const existing = prev[userId];
7130
+ if (existing && existing >= lastReadAt) return prev;
7131
+ return { ...prev, [userId]: lastReadAt };
7132
+ });
7133
+ }
7134
+ break;
7135
+ }
6990
7136
  case "pong":
6991
7137
  break;
6992
7138
  case "error":
@@ -7023,16 +7169,27 @@ function useChatRoom(roomId, config, options = {}) {
7023
7169
  setIsConnected(false);
7024
7170
  setError(null);
7025
7171
  setTypingUsers([]);
7172
+ setOnlineUserIds([]);
7173
+ setReadReceipts({});
7026
7174
  setHasMoreHistory(true);
7175
+ setIsLoadingHistory(false);
7176
+ setIsInitialLoading(false);
7027
7177
  cursorRef.current = null;
7028
7178
  messageIdsRef.current = /* @__PURE__ */ new Set();
7179
+ lastSentWatermarkRef.current = null;
7180
+ pendingMarkRef.current = null;
7029
7181
  return;
7030
7182
  }
7031
7183
  setMessages([]);
7032
7184
  setTypingUsers([]);
7185
+ setOnlineUserIds([]);
7186
+ setReadReceipts({});
7033
7187
  setHasMoreHistory(true);
7188
+ setIsInitialLoading(true);
7034
7189
  cursorRef.current = null;
7035
7190
  messageIdsRef.current = /* @__PURE__ */ new Set();
7191
+ lastSentWatermarkRef.current = null;
7192
+ pendingMarkRef.current = null;
7036
7193
  reconnectDelayRef.current = minReconnectDelay;
7037
7194
  void connect();
7038
7195
  return () => {
@@ -7048,12 +7205,16 @@ function useChatRoom(roomId, config, options = {}) {
7048
7205
  messages,
7049
7206
  sendMessage,
7050
7207
  sendTyping,
7208
+ markRead,
7051
7209
  isConnected,
7052
7210
  error,
7053
7211
  typingUsers,
7212
+ onlineUserIds,
7213
+ readReceipts,
7054
7214
  loadMoreHistory,
7055
7215
  hasMoreHistory,
7056
- isLoadingHistory
7216
+ isLoadingHistory,
7217
+ isInitialLoading
7057
7218
  };
7058
7219
  }
7059
7220
  var roleColors = {
@@ -7068,21 +7229,27 @@ function ChatRoomView({
7068
7229
  currentUserId,
7069
7230
  config,
7070
7231
  roomLabel,
7232
+ caseNumber,
7071
7233
  labels = {},
7072
7234
  roleLabel,
7235
+ onMarkedRead,
7073
7236
  className
7074
7237
  }) {
7075
7238
  const {
7076
7239
  messages,
7077
7240
  sendMessage,
7078
7241
  sendTyping,
7242
+ markRead,
7079
7243
  isConnected,
7080
7244
  error,
7081
7245
  typingUsers,
7246
+ onlineUserIds,
7247
+ readReceipts,
7082
7248
  loadMoreHistory,
7083
7249
  hasMoreHistory,
7084
- isLoadingHistory
7085
- } = useChatRoom(roomId, config);
7250
+ isLoadingHistory,
7251
+ isInitialLoading
7252
+ } = useChatRoom(roomId, config, { onMarkedRead });
7086
7253
  const [newMessage, setNewMessage] = React7.useState("");
7087
7254
  const [pendingAttachments, setPendingAttachments] = React7.useState([]);
7088
7255
  const scrollRef = React7.useRef(null);
@@ -7090,6 +7257,16 @@ function ChatRoomView({
7090
7257
  const fileInputRef = React7.useRef(null);
7091
7258
  const typingTimeoutRef = React7.useRef(null);
7092
7259
  const prevMessageCountRef = React7.useRef(0);
7260
+ const counterpartOnline = React7.useMemo(
7261
+ () => onlineUserIds.some((id) => id !== currentUserId),
7262
+ [onlineUserIds, currentUserId]
7263
+ );
7264
+ React7.useEffect(() => {
7265
+ if (isInitialLoading || messages.length === 0) return;
7266
+ const latest = messages[messages.length - 1];
7267
+ if (!latest) return;
7268
+ markRead(latest.id, latest.createdAt);
7269
+ }, [messages, isInitialLoading, markRead]);
7093
7270
  React7.useEffect(() => {
7094
7271
  const el = scrollRef.current;
7095
7272
  if (!el) return;
@@ -7202,27 +7379,50 @@ function ChatRoomView({
7202
7379
  };
7203
7380
  const getAttachmentUrl = (attachmentId) => `${config.baseUrl}/rooms/${roomId}/attachments/${attachmentId}`;
7204
7381
  const getRoleLabel = (role) => roleLabel ? roleLabel(role) : role;
7205
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex h-full flex-col", className), children: [
7206
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-shrink-0 flex items-center justify-between border-b px-4 py-3", children: [
7207
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
7208
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquare, { className: "h-4 w-4 text-primary", "aria-hidden": "true" }),
7209
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: roomLabel ?? "Chat" })
7382
+ const isMessageSeen = (message) => {
7383
+ if (message.senderId !== currentUserId) return false;
7384
+ return Object.entries(readReceipts).some(
7385
+ ([userId, lastReadAt]) => userId !== currentUserId && lastReadAt >= message.createdAt
7386
+ );
7387
+ };
7388
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex h-full min-h-0 flex-col", className), children: [
7389
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-shrink-0 flex items-center justify-between border-b px-4 py-2.5", children: [
7390
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
7391
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
7392
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium truncate", children: roomLabel ?? "Chat" }),
7393
+ caseNumber && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground truncate", children: caseNumber })
7394
+ ] }),
7395
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-0.5 flex items-center gap-1.5", children: [
7396
+ /* @__PURE__ */ jsxRuntime.jsx(
7397
+ lucideReact.Circle,
7398
+ {
7399
+ className: cn(
7400
+ "h-2 w-2 fill-current",
7401
+ counterpartOnline ? "text-emerald-500" : "text-muted-foreground/40"
7402
+ )
7403
+ }
7404
+ ),
7405
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] text-muted-foreground", children: counterpartOnline ? labels.online ?? "Online" : labels.offline ?? "Offline" })
7406
+ ] })
7210
7407
  ] }),
7211
7408
  /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
7212
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1.5", children: isConnected ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Wifi, { className: "h-3.5 w-3.5 text-green-500" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.WifiOff, { className: "h-3.5 w-3.5 text-destructive" }) }) }),
7409
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1.5", children: isConnected ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Wifi, { className: "h-3.5 w-3.5 text-emerald-500" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.WifiOff, { className: "h-3.5 w-3.5 text-destructive" }) }) }),
7213
7410
  /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: isConnected ? "Connected" : error ?? "Reconnecting..." })
7214
7411
  ] }) })
7215
7412
  ] }),
7216
7413
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
7217
- /* @__PURE__ */ jsxRuntime.jsxs(
7414
+ /* @__PURE__ */ jsxRuntime.jsx(
7218
7415
  "div",
7219
7416
  {
7220
7417
  ref: scrollRef,
7221
7418
  onScroll: handleScroll,
7222
7419
  className: "flex-1 overflow-y-auto p-3",
7223
- children: [
7420
+ children: isInitialLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col items-center justify-center py-8", children: [
7421
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-6 w-6 animate-spin text-muted-foreground" }),
7422
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: labels.loading ?? "Loading messages..." })
7423
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7224
7424
  isLoadingHistory && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center py-2", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin text-muted-foreground" }) }),
7225
- messages.length === 0 && !isLoadingHistory ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col items-center justify-center py-8 text-center", children: [
7425
+ messages.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col items-center justify-center py-8 text-center", children: [
7226
7426
  /* @__PURE__ */ jsxRuntime.jsx(
7227
7427
  lucideReact.MessageSquare,
7228
7428
  {
@@ -7231,112 +7431,132 @@ function ChatRoomView({
7231
7431
  }
7232
7432
  ),
7233
7433
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: labels.noMessages ?? "No messages yet" })
7234
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: Object.entries(groupedMessages).map(([date, dateMessages]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
7235
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "my-3 flex items-center gap-3", children: [
7236
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px flex-1 bg-border" }),
7237
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2 text-xs text-muted-foreground", children: date }),
7238
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px flex-1 bg-border" })
7239
- ] }),
7240
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: dateMessages.map((message) => {
7241
- const isCurrentUser = message.senderId === currentUserId;
7242
- return /* @__PURE__ */ jsxRuntime.jsxs(
7243
- "div",
7244
- {
7245
- className: cn(
7246
- "flex gap-2",
7247
- isCurrentUser ? "flex-row-reverse" : "flex-row"
7248
- ),
7249
- children: [
7250
- /* @__PURE__ */ jsxRuntime.jsx(
7251
- "div",
7252
- {
7253
- className: cn(
7254
- "flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-full text-xs font-medium",
7255
- roleColors[message.senderRole] ?? roleColors.client
7256
- ),
7257
- children: (message.senderName ?? message.senderId).split(" ").map((n) => n[0]).join("").slice(0, 2).toUpperCase()
7258
- }
7434
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: Object.entries(groupedMessages).map(
7435
+ ([date, dateMessages]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
7436
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "my-3 flex items-center gap-3", children: [
7437
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px flex-1 bg-border" }),
7438
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2 text-xs text-muted-foreground", children: date }),
7439
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px flex-1 bg-border" })
7440
+ ] }),
7441
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: dateMessages.map((message) => {
7442
+ if (message.senderRole === "system") {
7443
+ return /* @__PURE__ */ jsxRuntime.jsx(
7444
+ "div",
7445
+ {
7446
+ className: "flex justify-center py-1",
7447
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex max-w-[90%] items-center gap-1.5 rounded-full border bg-muted/60 px-3 py-1 text-[11px] text-muted-foreground", children: [
7448
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Info, { className: "h-3 w-3 flex-shrink-0" }),
7449
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-center", children: message.content })
7450
+ ] })
7451
+ },
7452
+ message.id
7453
+ );
7454
+ }
7455
+ const isCurrentUser = message.senderId === currentUserId;
7456
+ const seen = isMessageSeen(message);
7457
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7458
+ "div",
7459
+ {
7460
+ className: cn(
7461
+ "flex gap-2",
7462
+ isCurrentUser ? "flex-row-reverse" : "flex-row"
7259
7463
  ),
7260
- /* @__PURE__ */ jsxRuntime.jsxs(
7261
- "div",
7262
- {
7263
- className: cn(
7264
- "flex max-w-[80%] flex-col",
7265
- isCurrentUser ? "items-end" : "items-start"
7266
- ),
7267
- children: [
7268
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-0.5 flex items-center gap-1.5", children: [
7269
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-foreground", children: message.senderName ?? message.senderId.slice(0, 8) }),
7270
- /* @__PURE__ */ jsxRuntime.jsx(
7271
- "span",
7464
+ children: [
7465
+ /* @__PURE__ */ jsxRuntime.jsx(
7466
+ "div",
7467
+ {
7468
+ className: cn(
7469
+ "flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-full text-xs font-medium",
7470
+ roleColors[message.senderRole] ?? roleColors.client
7471
+ ),
7472
+ children: (message.senderName ?? message.senderId).split(" ").map((n) => n[0]).join("").slice(0, 2).toUpperCase()
7473
+ }
7474
+ ),
7475
+ /* @__PURE__ */ jsxRuntime.jsxs(
7476
+ "div",
7477
+ {
7478
+ className: cn(
7479
+ "flex max-w-[80%] flex-col",
7480
+ isCurrentUser ? "items-end" : "items-start"
7481
+ ),
7482
+ children: [
7483
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-0.5 flex items-center gap-1.5", children: [
7484
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-foreground", children: message.senderName ?? message.senderId.slice(0, 8) }),
7485
+ /* @__PURE__ */ jsxRuntime.jsx(
7486
+ "span",
7487
+ {
7488
+ className: cn(
7489
+ "rounded px-1 py-0.5 text-[10px] font-medium",
7490
+ roleColors[message.senderRole] ?? ""
7491
+ ),
7492
+ children: getRoleLabel(message.senderRole)
7493
+ }
7494
+ ),
7495
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: formatTime2(message.createdAt) })
7496
+ ] }),
7497
+ message.content && /* @__PURE__ */ jsxRuntime.jsx(
7498
+ "div",
7272
7499
  {
7273
7500
  className: cn(
7274
- "rounded px-1 py-0.5 text-[10px] font-medium",
7275
- roleColors[message.senderRole] ?? ""
7501
+ "rounded-2xl px-3 py-2 text-sm shadow-sm",
7502
+ isCurrentUser ? "rounded-br-md bg-primary text-primary-foreground" : "rounded-bl-md bg-muted text-foreground"
7276
7503
  ),
7277
- children: getRoleLabel(message.senderRole)
7504
+ children: message.content
7278
7505
  }
7279
7506
  ),
7280
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: formatTime2(message.createdAt) })
7281
- ] }),
7282
- message.content && /* @__PURE__ */ jsxRuntime.jsx(
7283
- "div",
7284
- {
7285
- className: cn(
7286
- "rounded-xl px-3 py-2 text-sm",
7287
- isCurrentUser ? "rounded-br-sm bg-primary text-primary-foreground" : "rounded-bl-sm bg-muted text-foreground"
7288
- ),
7289
- children: message.content
7290
- }
7291
- ),
7292
- message.attachments.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 flex flex-col gap-1", children: message.attachments.map(
7293
- (att) => att.mimeType.startsWith("image/") ? /* @__PURE__ */ jsxRuntime.jsx(
7294
- "a",
7295
- {
7296
- href: getAttachmentUrl(att.id),
7297
- target: "_blank",
7298
- rel: "noopener noreferrer",
7299
- className: "block max-w-[200px] overflow-hidden rounded-lg border",
7300
- children: /* @__PURE__ */ jsxRuntime.jsx(
7301
- "img",
7302
- {
7303
- src: getAttachmentUrl(att.id),
7304
- alt: att.fileName,
7305
- className: "h-auto w-full object-cover",
7306
- loading: "lazy"
7307
- }
7308
- )
7309
- },
7310
- att.id
7311
- ) : /* @__PURE__ */ jsxRuntime.jsxs(
7312
- "a",
7313
- {
7314
- href: getAttachmentUrl(att.id),
7315
- target: "_blank",
7316
- rel: "noopener noreferrer",
7317
- className: "flex items-center gap-2 rounded-lg border bg-muted/50 px-2 py-1.5 text-xs transition-colors hover:bg-muted",
7318
- children: [
7319
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileIcon, { className: "h-3.5 w-3.5 flex-shrink-0 text-muted-foreground" }),
7320
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
7321
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate font-medium", children: att.fileName }),
7322
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] text-muted-foreground", children: formatFileSize(att.fileSize) })
7323
- ] }),
7324
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { className: "h-3.5 w-3.5 flex-shrink-0 text-muted-foreground" })
7325
- ]
7326
- },
7327
- att.id
7328
- )
7329
- ) })
7330
- ]
7331
- }
7332
- )
7333
- ]
7334
- },
7335
- message.id
7336
- );
7337
- }) })
7338
- ] }, date)) })
7339
- ]
7507
+ message.attachments.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 flex flex-col gap-1", children: message.attachments.map(
7508
+ (att) => att.mimeType.startsWith("image/") ? /* @__PURE__ */ jsxRuntime.jsx(
7509
+ "a",
7510
+ {
7511
+ href: getAttachmentUrl(att.id),
7512
+ target: "_blank",
7513
+ rel: "noopener noreferrer",
7514
+ className: "block max-w-[200px] overflow-hidden rounded-lg border",
7515
+ children: /* @__PURE__ */ jsxRuntime.jsx(
7516
+ "img",
7517
+ {
7518
+ src: getAttachmentUrl(att.id),
7519
+ alt: att.fileName,
7520
+ className: "h-auto w-full object-cover",
7521
+ loading: "lazy"
7522
+ }
7523
+ )
7524
+ },
7525
+ att.id
7526
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(
7527
+ "a",
7528
+ {
7529
+ href: getAttachmentUrl(att.id),
7530
+ target: "_blank",
7531
+ rel: "noopener noreferrer",
7532
+ className: "flex items-center gap-2 rounded-lg border bg-muted/50 px-2 py-1.5 text-xs transition-colors hover:bg-muted",
7533
+ children: [
7534
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileIcon, { className: "h-3.5 w-3.5 flex-shrink-0 text-muted-foreground" }),
7535
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
7536
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate font-medium", children: att.fileName }),
7537
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] text-muted-foreground", children: formatFileSize(att.fileSize) })
7538
+ ] }),
7539
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { className: "h-3.5 w-3.5 flex-shrink-0 text-muted-foreground" })
7540
+ ]
7541
+ },
7542
+ att.id
7543
+ )
7544
+ ) }),
7545
+ isCurrentUser && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-0.5 flex items-center gap-0.5 text-[10px] text-muted-foreground", children: seen ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7546
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCheck, { className: "h-3 w-3 text-primary" }),
7547
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: labels.seen ?? "Seen" })
7548
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3 w-3" }) })
7549
+ ]
7550
+ }
7551
+ )
7552
+ ]
7553
+ },
7554
+ message.id
7555
+ );
7556
+ }) })
7557
+ ] }, date)
7558
+ ) })
7559
+ ] })
7340
7560
  }
7341
7561
  ),
7342
7562
  typingUsers.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 px-3 py-1", children: /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground italic", children: [
@@ -7431,16 +7651,45 @@ function ChatRoomView({
7431
7651
  ] })
7432
7652
  ] });
7433
7653
  }
7654
+ function Input({ className, type, ...props }) {
7655
+ return /* @__PURE__ */ jsxRuntime.jsx(
7656
+ "input",
7657
+ {
7658
+ type,
7659
+ "data-slot": "input",
7660
+ className: cn(
7661
+ "h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30",
7662
+ "focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
7663
+ "aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
7664
+ className
7665
+ ),
7666
+ ...props
7667
+ }
7668
+ );
7669
+ }
7434
7670
  var roomTypeLabels = {
7435
7671
  client_agent: "Client \u2194 Agent",
7436
7672
  dealer_agent: "Dealer \u2194 Agent"
7437
7673
  };
7674
+ var statusToneClasses = {
7675
+ success: "bg-emerald-500/10 text-emerald-700 dark:text-emerald-400 border-emerald-500/20",
7676
+ warning: "bg-amber-500/10 text-amber-700 dark:text-amber-400 border-amber-500/20",
7677
+ destructive: "bg-destructive/10 text-destructive border-destructive/20",
7678
+ info: "bg-primary/10 text-primary border-primary/20",
7679
+ neutral: "bg-muted text-muted-foreground border-border"
7680
+ };
7681
+ var roomTypeIconClasses = {
7682
+ client_agent: "bg-blue-500/10 text-blue-600 dark:text-blue-400",
7683
+ dealer_agent: "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400"
7684
+ };
7438
7685
  function ChatSidebar({
7439
7686
  currentUserId,
7440
7687
  config,
7441
7688
  labels = {},
7442
7689
  roleLabel,
7443
7690
  roomTypeLabel,
7691
+ statusLabel,
7692
+ statusTone,
7444
7693
  mobileTopOffset,
7445
7694
  className
7446
7695
  }) {
@@ -7451,9 +7700,12 @@ function ChatSidebar({
7451
7700
  isLoading,
7452
7701
  activeCaseId,
7453
7702
  activeRoomId,
7703
+ searchQuery,
7704
+ setSearchQuery,
7454
7705
  close,
7455
7706
  selectRoom,
7456
- back
7707
+ back,
7708
+ clearRoomUnread
7457
7709
  } = useChatSidebar();
7458
7710
  React7.useEffect(() => {
7459
7711
  if (!isOpen || typeof window === "undefined") return;
@@ -7469,12 +7721,24 @@ function ChatSidebar({
7469
7721
  document.body.style.overflow = "";
7470
7722
  };
7471
7723
  }, [isOpen]);
7724
+ const filteredConversations = React7.useMemo(() => {
7725
+ const q = searchQuery.trim().toLowerCase();
7726
+ if (!q) return conversations;
7727
+ return conversations.filter(
7728
+ (c) => c.caseNumber.toLowerCase().includes(q) || (c.clientName?.toLowerCase().includes(q) ?? false)
7729
+ );
7730
+ }, [conversations, searchQuery]);
7472
7731
  if (!isOpen) return null;
7473
7732
  const getRoomTypeLabel = (type) => {
7474
7733
  if (roomTypeLabel) return roomTypeLabel(type);
7475
7734
  return roomTypeLabels[type] ?? type;
7476
7735
  };
7736
+ const getStatusLabel = (status) => statusLabel ? statusLabel(status) : status;
7737
+ const getStatusTone = (status) => statusTone?.(status) ?? "neutral";
7477
7738
  const activeConversation = activeCaseId ? conversations.find((c) => c.caseId === activeCaseId) : null;
7739
+ const activeRoom = activeConversation?.rooms.find(
7740
+ (r2) => r2.id === activeRoomId
7741
+ );
7478
7742
  const cssVars = {
7479
7743
  "--sidebar-top": mobileTopOffset ?? "0px"
7480
7744
  };
@@ -7505,40 +7769,99 @@ function ChatSidebar({
7505
7769
  }
7506
7770
  )
7507
7771
  ] }),
7772
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b px-3 py-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
7773
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }),
7774
+ /* @__PURE__ */ jsxRuntime.jsx(
7775
+ Input,
7776
+ {
7777
+ value: searchQuery,
7778
+ onChange: (e) => setSearchQuery(e.target.value),
7779
+ placeholder: labels.searchPlaceholder ?? "Search by case or client...",
7780
+ className: "h-8 pl-8 text-sm"
7781
+ }
7782
+ )
7783
+ ] }) }),
7508
7784
  /* @__PURE__ */ jsxRuntime.jsx(ScrollArea, { className: "flex-1", children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-12", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-5 w-5 animate-spin text-muted-foreground" }) }) : conversations.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center px-4", children: [
7509
7785
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquare, { className: "mb-3 h-8 w-8 text-muted-foreground/50" }),
7510
7786
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: labels.noConversations ?? "No conversations yet" })
7511
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-1", children: conversations.map((conv) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-2", children: [
7512
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-2 pt-3 pb-1", children: [
7513
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
7514
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold text-foreground", children: conv.caseNumber }),
7515
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded bg-muted px-1.5 py-0.5 text-[10px] text-muted-foreground", children: conv.caseStatus })
7516
- ] }),
7517
- conv.clientName && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground truncate", children: conv.clientName })
7518
- ] }),
7519
- conv.rooms.map((room) => /* @__PURE__ */ jsxRuntime.jsxs(
7520
- "button",
7787
+ ] }) : filteredConversations.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center px-4", children: [
7788
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "mb-3 h-8 w-8 text-muted-foreground/50" }),
7789
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: labels.noResults ?? "No matching conversations" })
7790
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2 p-3", children: filteredConversations.map((conv) => {
7791
+ const caseUnread = conv.rooms.reduce(
7792
+ (sum, r2) => sum + (r2.unreadCount ?? 0),
7793
+ 0
7794
+ );
7795
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7796
+ "div",
7521
7797
  {
7522
- type: "button",
7523
- onClick: () => selectRoom(room.id, conv.caseId),
7524
- className: cn(
7525
- "flex w-full items-center justify-between rounded-md px-2 py-2 text-left transition-colors hover:bg-accent",
7526
- activeRoomId === room.id && "bg-accent"
7527
- ),
7798
+ className: "rounded-lg border bg-card shadow-sm",
7528
7799
  children: [
7529
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
7530
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageSquare, { className: "h-3.5 w-3.5 flex-shrink-0 text-muted-foreground" }),
7531
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm truncate", children: getRoomTypeLabel(room.type) })
7800
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2 border-b bg-muted/40 px-3 py-2.5", children: [
7801
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
7802
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
7803
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold text-foreground truncate", children: conv.caseNumber }),
7804
+ caseUnread > 0 && /* @__PURE__ */ jsxRuntime.jsx(
7805
+ "span",
7806
+ {
7807
+ className: "h-2 w-2 flex-shrink-0 rounded-full bg-primary",
7808
+ "aria-label": `${caseUnread} unread`
7809
+ }
7810
+ )
7811
+ ] }),
7812
+ conv.clientName && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground truncate", children: conv.clientName })
7813
+ ] }),
7814
+ /* @__PURE__ */ jsxRuntime.jsx(
7815
+ "span",
7816
+ {
7817
+ className: cn(
7818
+ "flex-shrink-0 rounded-full border px-2 py-0.5 text-[10px] font-medium",
7819
+ statusToneClasses[getStatusTone(conv.caseStatus)]
7820
+ ),
7821
+ children: getStatusLabel(conv.caseStatus)
7822
+ }
7823
+ )
7532
7824
  ] }),
7533
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 flex-shrink-0", children: [
7534
- room.lastMessageAt && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: formatRelativeTime(room.lastMessageAt) }),
7535
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-3.5 w-3.5 text-muted-foreground" })
7536
- ] })
7825
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-1 divide-y", children: conv.rooms.map((room) => {
7826
+ const RoomIcon = room.type === "dealer_agent" ? lucideReact.Store : lucideReact.User;
7827
+ const unread = room.unreadCount ?? 0;
7828
+ const iconClasses = roomTypeIconClasses[room.type] ?? "bg-muted text-muted-foreground";
7829
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7830
+ "button",
7831
+ {
7832
+ type: "button",
7833
+ onClick: () => selectRoom(room.id, conv.caseId),
7834
+ className: cn(
7835
+ "flex w-full items-center gap-2.5 py-2.5 pl-4 pr-3 text-left transition-colors hover:bg-accent/60",
7836
+ activeRoomId === room.id && "bg-accent"
7837
+ ),
7838
+ children: [
7839
+ /* @__PURE__ */ jsxRuntime.jsx(
7840
+ "div",
7841
+ {
7842
+ className: cn(
7843
+ "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full",
7844
+ iconClasses
7845
+ ),
7846
+ children: /* @__PURE__ */ jsxRuntime.jsx(RoomIcon, { className: "h-3.5 w-3.5" })
7847
+ }
7848
+ ),
7849
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
7850
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium truncate", children: getRoomTypeLabel(room.type) }),
7851
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] text-muted-foreground", children: room.lastMessageAt ? formatRelativeTime(room.lastMessageAt) : labels.noMessagesShort ?? "No messages" })
7852
+ ] }),
7853
+ unread > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-5 min-w-5 flex-shrink-0 items-center justify-center rounded-full bg-primary px-1.5 text-[10px] font-semibold text-primary-foreground", children: unread > 99 ? "99+" : unread }),
7854
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4 flex-shrink-0 text-muted-foreground" })
7855
+ ]
7856
+ },
7857
+ room.id
7858
+ );
7859
+ }) })
7537
7860
  ]
7538
7861
  },
7539
- room.id
7540
- ))
7541
- ] }, conv.caseId)) }) })
7862
+ conv.caseId
7863
+ );
7864
+ }) }) })
7542
7865
  ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7543
7866
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 border-b px-3 py-2", children: [
7544
7867
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -7552,8 +7875,11 @@ function ChatSidebar({
7552
7875
  }
7553
7876
  ),
7554
7877
  activeConversation && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
7555
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium truncate", children: activeConversation.caseNumber }),
7556
- activeConversation.clientName && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground truncate", children: activeConversation.clientName })
7878
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium truncate", children: activeRoom ? getRoomTypeLabel(activeRoom.type) : activeConversation.caseNumber }),
7879
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground truncate", children: [
7880
+ activeConversation.caseNumber,
7881
+ activeConversation.clientName ? ` \xB7 ${activeConversation.clientName}` : ""
7882
+ ] })
7557
7883
  ] }),
7558
7884
  /* @__PURE__ */ jsxRuntime.jsx(
7559
7885
  Button,
@@ -7572,8 +7898,11 @@ function ChatSidebar({
7572
7898
  roomId: activeRoomId,
7573
7899
  currentUserId,
7574
7900
  config,
7901
+ roomLabel: activeRoom ? getRoomTypeLabel(activeRoom.type) : void 0,
7902
+ caseNumber: activeConversation?.caseNumber,
7575
7903
  labels,
7576
7904
  roleLabel,
7905
+ onMarkedRead: clearRoomUnread,
7577
7906
  className: "flex-1"
7578
7907
  }
7579
7908
  )
@@ -10293,22 +10622,6 @@ function USAddressInput({
10293
10622
  ] })
10294
10623
  ] });
10295
10624
  }
10296
- function Input({ className, type, ...props }) {
10297
- return /* @__PURE__ */ jsxRuntime.jsx(
10298
- "input",
10299
- {
10300
- type,
10301
- "data-slot": "input",
10302
- className: cn(
10303
- "h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30",
10304
- "focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
10305
- "aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
10306
- className
10307
- ),
10308
- ...props
10309
- }
10310
- );
10311
- }
10312
10625
  var phoneInputGroupClass = "flex h-9 w-full gap-0 overflow-hidden rounded-md border border-input bg-transparent shadow-xs transition-[color,box-shadow] [--PhoneInputCountrySelect-marginRight:0] focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50 dark:bg-input/30 [&_.PhoneInputCountry]:mr-0";
10313
10626
  var PhoneInput = React7__namespace.forwardRef(
10314
10627
  ({ className, onChange, value, defaultCountry = "MX", ...props }, ref) => {